1 43 44 package org.jfree.xml.util; 45 46 import java.io.BufferedInputStream ; 47 import java.io.InputStream ; 48 import java.net.URL ; 49 import java.util.Stack ; 50 51 import javax.xml.parsers.SAXParser ; 52 import javax.xml.parsers.SAXParserFactory ; 53 54 import org.jfree.util.Log; 55 import org.jfree.util.ObjectUtilities; 56 import org.jfree.xml.CommentHandler; 57 import org.jfree.xml.ElementDefinitionException; 58 import org.xml.sax.Attributes ; 59 import org.xml.sax.InputSource ; 60 import org.xml.sax.SAXException ; 61 import org.xml.sax.XMLReader ; 62 import org.xml.sax.helpers.DefaultHandler ; 63 64 71 public abstract class AbstractModelReader { 72 73 74 private static final int STATE_START = 0; 75 76 77 private static final int IN_OBJECT = 1; 78 79 80 private static final int IGNORE_OBJECT = 2; 81 82 83 private static final int MAPPING_STATE = 3; 84 85 86 private static final int CONSTRUCTOR_STATE = 4; 87 88 91 private class SAXModelHandler extends DefaultHandler { 92 93 94 private URL resource; 95 96 97 private int state; 98 99 100 private Stack openComments; 101 102 103 private boolean isInclude; 104 105 111 public SAXModelHandler(final URL resource, final boolean isInclude) { 112 if (resource == null) { 113 throw new NullPointerException (); 114 } 115 this.resource = resource; 116 this.openComments = new Stack (); 117 this.isInclude = isInclude; 118 } 119 120 139 public void startElement(final String uri, final String localName, 140 final String qName, final Attributes attributes) 141 throws SAXException { 142 143 setOpenComment(getCommentHandler().getComments()); 144 this.openComments.push(getOpenComment()); 145 setCloseComment(null); 146 147 try { 148 149 if (!this.isInclude && qName.equals(ClassModelTags.OBJECTS_TAG)) { 150 startRootDocument(); 152 return; 153 } 154 155 if (getState() == STATE_START) { 156 startRootElement(qName, attributes); 157 } 158 else if (getState() == IGNORE_OBJECT) { 159 return; 160 } 161 else if (getState() == IN_OBJECT) { 162 startObjectElement(qName, attributes); 163 } 164 else if (getState() == MAPPING_STATE) { 165 if (!qName.equals(ClassModelTags.TYPE_TAG)) { 166 throw new SAXException ("Expected 'type' tag"); 167 } 168 final String name = attributes.getValue(ClassModelTags.NAME_ATTR); 169 final String target = attributes.getValue(ClassModelTags.CLASS_ATTR); 170 handleMultiplexMapping(name, target); 171 } 172 else if (getState() == CONSTRUCTOR_STATE) { 173 if (!qName.equals(ClassModelTags.PARAMETER_TAG)) { 174 throw new SAXException ("Expected 'parameter' tag"); 175 } 176 final String parameterClass = attributes.getValue(ClassModelTags.CLASS_ATTR); 177 final String tagName = attributes.getValue(ClassModelTags.PROPERTY_ATTR); handleConstructorDefinition(tagName, parameterClass); 179 } 180 } 181 catch (ObjectDescriptionException e) { 182 throw new SAXException (e); 183 } 184 finally { 185 getCommentHandler().clearComments(); 186 } 187 } 188 189 204 public void endElement(final String uri, final String localName, final String qName) 205 throws SAXException { 206 207 setOpenComment((String []) this.openComments.pop()); 208 setCloseComment(getCommentHandler().getComments()); 209 210 try { 211 if (!this.isInclude && qName.equals(ClassModelTags.OBJECTS_TAG)) { 212 endRootDocument(); 213 return; 214 } 215 216 if (qName.equals(ClassModelTags.OBJECT_TAG)) { 217 if (getState() != IGNORE_OBJECT) { 218 endObjectDefinition(); 219 } 220 setState(STATE_START); 221 } 222 else if (qName.equals(ClassModelTags.MAPPING_TAG)) { 223 setState(STATE_START); 224 endMultiplexMapping(); 225 } 226 else if (qName.equals(ClassModelTags.CONSTRUCTOR_TAG)) { 227 if (getState() != IGNORE_OBJECT) { 228 setState(IN_OBJECT); 229 } 230 } 231 } 232 catch (ObjectDescriptionException e) { 233 throw new SAXException (e); 234 } 235 finally { 236 getCommentHandler().clearComments(); 237 } 238 } 239 240 251 private void startObjectElement(final String qName, final Attributes attributes) 252 throws ObjectDescriptionException { 253 if (qName.equals(ClassModelTags.CONSTRUCTOR_TAG)) { 254 setState(CONSTRUCTOR_STATE); 255 } 256 else if (qName.equals(ClassModelTags.LOOKUP_PROPERTY_TAG)) { 257 final String name = attributes.getValue(ClassModelTags.NAME_ATTR); 258 final String lookupKey = attributes.getValue(ClassModelTags.LOOKUP_ATTR); 259 handleLookupDefinition(name, lookupKey); 260 } 261 else if (qName.equals(ClassModelTags.IGNORED_PROPERTY_TAG)) { 262 final String name = attributes.getValue(ClassModelTags.NAME_ATTR); 263 handleIgnoredProperty(name); 264 } 265 else if (qName.equals(ClassModelTags.ELEMENT_PROPERTY_TAG)) { 266 final String elementAtt = attributes.getValue(ClassModelTags.ELEMENT_ATTR); 267 final String name = attributes.getValue(ClassModelTags.NAME_ATTR); 268 handleElementDefinition(name, elementAtt); 269 } 270 else if (qName.equals(ClassModelTags.ATTRIBUTE_PROPERTY_TAG)) { 271 final String name = attributes.getValue(ClassModelTags.NAME_ATTR); 272 final String attribName = attributes.getValue(ClassModelTags.ATTRIBUTE_ATTR); 273 final String handler = attributes.getValue(ClassModelTags.ATTRIBUTE_HANDLER_ATTR); 274 handleAttributeDefinition(name, attribName, handler); 275 } 276 } 277 278 290 private void startRootElement(final String qName, final Attributes attributes) 291 throws SAXException , ObjectDescriptionException { 292 293 if (qName.equals(ClassModelTags.INCLUDE_TAG)) { 294 if (this.isInclude) { 295 Log.warn("Ignored nested include tag."); 296 return; 297 } 298 final String src = attributes.getValue(ClassModelTags.SOURCE_ATTR); 299 try { 300 final URL url = new URL (this.resource, src); 301 startIncludeHandling(url); 302 parseXmlDocument(url, true); 303 endIncludeHandling(); 304 } 305 catch (Exception ioe) { 306 throw new ElementDefinitionException 307 (ioe, "Unable to include file from " + src); 308 } 309 } 310 else if (qName.equals(ClassModelTags.OBJECT_TAG)) { 311 setState(IN_OBJECT); 312 final String className = attributes.getValue(ClassModelTags.CLASS_ATTR); 313 String register = attributes.getValue(ClassModelTags.REGISTER_NAMES_ATTR); 314 if (register != null && register.length() == 0) { 315 register = null; 316 } 317 final boolean ignored = "true".equals(attributes.getValue(ClassModelTags.IGNORE_ATTR)); 318 if (!startObjectDefinition(className, register, ignored)) { 319 setState(IGNORE_OBJECT); 320 } 321 } 322 else if (qName.equals(ClassModelTags.MANUAL_TAG)) { 323 final String className = attributes.getValue(ClassModelTags.CLASS_ATTR); 324 final String readHandler = attributes.getValue(ClassModelTags.READ_HANDLER_ATTR); 325 final String writeHandler = attributes.getValue(ClassModelTags.WRITE_HANDLER_ATTR); 326 handleManualMapping(className, readHandler, writeHandler); 327 } 328 else if (qName.equals(ClassModelTags.MAPPING_TAG)) { 329 setState(MAPPING_STATE); 330 final String typeAttr = attributes.getValue(ClassModelTags.TYPE_ATTR); 331 final String baseClass = attributes.getValue(ClassModelTags.BASE_CLASS_ATTR); 332 startMultiplexMapping(baseClass, typeAttr); 333 } 334 } 335 336 341 private int getState() { 342 return this.state; 343 } 344 345 350 private void setState(final int state) { 351 this.state = state; 352 } 353 } 354 355 356 private CommentHandler commentHandler; 357 358 359 private String [] closeComment; 360 361 362 private String [] openComment; 363 364 367 public AbstractModelReader() { 368 this.commentHandler = new CommentHandler(); 369 } 370 371 376 protected CommentHandler getCommentHandler() { 377 return this.commentHandler; 378 } 379 380 385 protected String [] getCloseComment() { 386 return this.closeComment; 387 } 388 389 394 protected String [] getOpenComment() { 395 return this.openComment; 396 } 397 398 403 protected void setCloseComment(final String [] closeComment) { 404 this.closeComment = closeComment; 405 } 406 407 412 protected void setOpenComment(final String [] openComment) { 413 this.openComment = openComment; 414 } 415 416 423 protected void parseXml(final URL resource) throws ObjectDescriptionException { 424 parseXmlDocument(resource, false); 425 } 426 427 437 protected void parseXmlDocument(final URL resource, final boolean isInclude) 438 throws ObjectDescriptionException { 439 440 try { 441 final InputStream in = new BufferedInputStream (resource.openStream()); 442 final SAXParserFactory factory = SAXParserFactory.newInstance(); 443 final SAXParser saxParser = factory.newSAXParser(); 444 final XMLReader reader = saxParser.getXMLReader(); 445 446 final SAXModelHandler handler = new SAXModelHandler(resource, isInclude); 447 try { 448 reader.setProperty 449 ("http://xml.org/sax/properties/lexical-handler", 450 getCommentHandler()); 451 } 452 catch (SAXException se) { 453 Log.debug("Comments are not supported by this SAX implementation."); 454 } 455 reader.setContentHandler(handler); 456 reader.setDTDHandler(handler); 457 reader.setErrorHandler(handler); 458 reader.parse(new InputSource (in)); 459 in.close(); 460 } 461 catch (Exception e) { 462 Log.warn("Unable to load factory specifications", e); 464 throw new ObjectDescriptionException("Unable to load object factory specs.", e); 465 } 466 } 467 468 471 protected void startRootDocument() { 472 } 474 475 478 protected void endRootDocument() { 479 } 481 482 487 protected void startIncludeHandling(final URL resource) { 488 } 490 491 494 protected void endIncludeHandling() { 495 } 497 498 504 protected void handleIgnoredProperty(final String name) { 505 } 507 508 519 protected abstract boolean handleManualMapping(String className, String readHandler, 520 String writeHandler) throws ObjectDescriptionException; 521 522 535 protected abstract boolean startObjectDefinition(String className, String register, 536 boolean ignored) throws ObjectDescriptionException; 537 538 547 protected abstract void handleAttributeDefinition(String name, String attribName, 548 String handlerClass) 549 throws ObjectDescriptionException; 550 551 560 protected abstract void handleElementDefinition(String name, String element) 561 throws ObjectDescriptionException; 562 563 572 protected abstract void handleLookupDefinition(String name, String lookupKey) 573 throws ObjectDescriptionException; 574 575 580 protected abstract void endObjectDefinition() throws ObjectDescriptionException; 581 582 591 protected abstract void startMultiplexMapping(String className, String typeAttr); 592 593 602 protected abstract void handleMultiplexMapping(String typeName, String className) 603 throws ObjectDescriptionException; 604 605 610 protected abstract void endMultiplexMapping() throws ObjectDescriptionException; 611 612 620 protected abstract void handleConstructorDefinition(String propertyName, String parameterClass) 621 throws ObjectDescriptionException; 622 623 630 protected Class loadClass(final String className) { 631 if (className == null) { 632 return null; 633 } 634 if (className.startsWith("::")) { 635 return BasicTypeSupport.getClassRepresentation(className); 636 } 637 try { 638 return ObjectUtilities.getClassLoader(getClass()).loadClass(className); 639 } 640 catch (Exception e) { 641 Log.warn("Unable to load class", e); 643 return null; 644 } 645 } 646 647 } 648 | Popular Tags |