001 /* 002 * JBoss, Home of Professional Open Source. 003 * Copyright 2008, Red Hat Middleware LLC, and individual contributors 004 * as indicated by the @author tags. See the copyright.txt file in the 005 * distribution for a full listing of individual contributors. 006 * 007 * This is free software; you can redistribute it and/or modify it 008 * under the terms of the GNU Lesser General Public License as 009 * published by the Free Software Foundation; either version 2.1 of 010 * the License, or (at your option) any later version. 011 * 012 * This software is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this software; if not, write to the Free 019 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 020 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 021 */ 022 package org.jboss.dna.graph.xml; 023 024 import java.io.InputStream; 025 import java.util.ArrayList; 026 import java.util.HashMap; 027 import java.util.LinkedList; 028 import java.util.List; 029 import java.util.Map; 030 import org.jboss.dna.common.monitor.ProgressMonitor; 031 import org.jboss.dna.common.util.StringUtil; 032 import org.jboss.dna.graph.GraphI18n; 033 import org.jboss.dna.graph.properties.Name; 034 import org.jboss.dna.graph.properties.NameFactory; 035 import org.jboss.dna.graph.properties.NamespaceRegistry; 036 import org.jboss.dna.graph.properties.Path; 037 import org.jboss.dna.graph.sequencers.SequencerContext; 038 import org.jboss.dna.graph.sequencers.SequencerOutput; 039 import org.jboss.dna.graph.sequencers.StreamSequencer; 040 import org.xml.sax.Attributes; 041 import org.xml.sax.InputSource; 042 import org.xml.sax.SAXException; 043 import org.xml.sax.SAXNotRecognizedException; 044 import org.xml.sax.SAXNotSupportedException; 045 import org.xml.sax.SAXParseException; 046 import org.xml.sax.XMLReader; 047 import org.xml.sax.ext.DefaultHandler2; 048 import org.xml.sax.helpers.XMLReaderFactory; 049 050 /** 051 * @author John Verhaeg 052 */ 053 public class XmlSequencer implements StreamSequencer { 054 055 private static final String DEFAULT_PRIMARY_TYPE = "nt:unstructured"; 056 private static final String DECL_HANDLER_FEATURE = "http://xml.org/sax/properties/declaration-handler"; 057 private static final String ENTITY_RESOLVER_2_FEATURE = "http://xml.org/sax/features/use-entity-resolver2"; 058 private static final String LEXICAL_HANDLER_FEATURE = "http://xml.org/sax/properties/lexical-handler"; 059 private static final String RESOLVE_DTD_URIS_FEATURE = "http://xml.org/sax/features/resolve-dtd-uris"; 060 private static final String LOAD_EXTERNAL_DTDS_FEATURE = "http://apache.org/xml/features/nonvalidating/load-external-dtd"; 061 062 /** 063 * {@inheritDoc} 064 * 065 * @see org.jboss.dna.graph.sequencers.StreamSequencer#sequence(InputStream, SequencerOutput, SequencerContext, 066 * ProgressMonitor) 067 */ 068 public void sequence( InputStream stream, 069 SequencerOutput output, 070 SequencerContext context, 071 ProgressMonitor monitor ) { 072 monitor.beginTask(100.0, GraphI18n.sequencingXmlDocument); 073 XMLReader reader; 074 try { 075 reader = XMLReaderFactory.createXMLReader(); 076 Handler handler = new Handler(output, context, monitor); 077 reader.setContentHandler(handler); 078 reader.setErrorHandler(handler); 079 // Ensure handler acting as entity resolver 2 080 reader.setProperty(DECL_HANDLER_FEATURE, handler); 081 // Ensure handler acting as lexical handler 082 reader.setProperty(LEXICAL_HANDLER_FEATURE, handler); 083 // Ensure handler acting as entity resolver 2 084 setFeature(reader, ENTITY_RESOLVER_2_FEATURE, true); 085 // Prevent loading of external DTDs 086 setFeature(reader, LOAD_EXTERNAL_DTDS_FEATURE, false); 087 // Prevent the resolving of DTD entities into fully-qualified URIS 088 setFeature(reader, RESOLVE_DTD_URIS_FEATURE, false); 089 // Parse XML document 090 reader.parse(new InputSource(stream)); 091 } catch (Exception error) { 092 context.getLogger(getClass()).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error); 093 monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error); 094 } finally { 095 monitor.done(); 096 } 097 } 098 099 /** 100 * Sets the reader's named feature to the supplied value, only if the feature is not already set to that value. This method 101 * does nothing if the feature is not known to the reader. 102 * 103 * @param reader the reader; may not be null 104 * @param featureName the name of the feature; may not be null 105 * @param value the value for the feature 106 */ 107 private void setFeature( XMLReader reader, 108 String featureName, 109 boolean value ) { 110 try { 111 if (reader.getFeature(featureName) != value) { 112 reader.setFeature(featureName, value); 113 } 114 } catch (SAXNotRecognizedException meansFeatureNotRecognized) { 115 } catch (SAXNotSupportedException meansFeatureNotSupported) { 116 } 117 } 118 119 private final class Handler extends DefaultHandler2 { 120 121 private final SequencerOutput output; 122 private final SequencerContext context; 123 private final ProgressMonitor monitor; 124 125 private double progress; 126 127 private Path path; // The DNA path of the node representing the current XML element 128 129 // Cached instances of the name factory and commonly referenced names 130 private final NameFactory nameFactory; 131 private Name primaryTypeName; 132 private Name defaultPrimaryType; 133 134 // Recursive map used to track the number of occurrences of names for elements under a particular path 135 private Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>(); 136 137 // The stack of recursive maps being processed, with the head entry being the map for the current path 138 private final LinkedList<Map<Name, List<IndexedName>>> nameToIndexedNamesMapStack = new LinkedList<Map<Name, List<IndexedName>>>(); 139 140 // The stack of XML namespace in scope, with the head entry being namespace of the closest ancestor element declaring a 141 // namespace. 142 private final LinkedList<String> nsStack = new LinkedList<String>(); 143 144 // Builder used to concatenate concurrent lines of CDATA into a single value. 145 private StringBuilder cDataBuilder; 146 147 // Builder used to concatenate concurrent lines of element content and entity evaluations into a single value. 148 private StringBuilder contentBuilder; 149 150 // The entity being processed 151 private String entity; 152 153 Handler( SequencerOutput output, 154 SequencerContext context, 155 ProgressMonitor monitor ) { 156 assert output != null; 157 assert monitor != null; 158 assert context != null; 159 this.output = output; 160 this.context = context; 161 this.monitor = monitor; 162 // Initialize path to a an empty path relative to the SequencerOutput's target path. 163 path = context.getFactories().getPathFactory().createRelativePath(); 164 // Cache name factory since it is frequently used 165 nameFactory = context.getFactories().getNameFactory(); 166 } 167 168 /** 169 * <p> 170 * {@inheritDoc} 171 * </p> 172 * 173 * @see org.xml.sax.ext.DefaultHandler2#attributeDecl(java.lang.String, java.lang.String, java.lang.String, 174 * java.lang.String, java.lang.String) 175 */ 176 @Override 177 public void attributeDecl( String name, 178 String name2, 179 String type, 180 String mode, 181 String value ) throws SAXException { 182 stopIfCancelled(); 183 } 184 185 /** 186 * <p> 187 * {@inheritDoc} 188 * </p> 189 * 190 * @see org.xml.sax.helpers.DefaultHandler#characters(char[], int, int) 191 */ 192 @Override 193 public void characters( char[] ch, 194 int start, 195 int length ) throws SAXException { 196 stopIfCancelled(); 197 String content = String.valueOf(ch, start, length); 198 // Check if data should be appended to previously parsed CDATA 199 if (cDataBuilder == null) { 200 // If content is for an entity, replace with entity reference 201 if (entity != null) { 202 content = '&' + entity + ';'; 203 } 204 // Check if first line of content 205 if (contentBuilder == null) { 206 contentBuilder = new StringBuilder(content); 207 } else { 208 // Append additional lines or entity evaluations to previous content, separated by a space 209 if (entity == null) { 210 contentBuilder.append(' '); 211 } 212 contentBuilder.append(content); 213 // Text within builder will be output when another element or CDATA is encountered 214 } 215 } else { 216 cDataBuilder.append(ch, start, length); 217 // Text within builder will be output at the end of CDATA 218 } 219 updateProgress(); 220 } 221 222 /** 223 * <p> 224 * {@inheritDoc} 225 * </p> 226 * 227 * @see org.xml.sax.ext.DefaultHandler2#comment(char[], int, int) 228 */ 229 @Override 230 public void comment( char[] ch, 231 int start, 232 int length ) throws SAXException { 233 stopIfCancelled(); 234 // Output separate nodes for each comment since multiple are allowed 235 startElement(DnaXmlLexicon.COMMENT); 236 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.COMMENT); 237 output.setProperty(path, DnaXmlLexicon.COMMENT_CONTENT, String.valueOf(ch, start, length)); 238 endElement(); 239 updateProgress(); 240 } 241 242 /** 243 * <p> 244 * {@inheritDoc} 245 * </p> 246 * 247 * @see org.xml.sax.ext.DefaultHandler2#elementDecl(java.lang.String, java.lang.String) 248 */ 249 @Override 250 public void elementDecl( String name, 251 String model ) throws SAXException { 252 stopIfCancelled(); 253 } 254 255 /** 256 * <p> 257 * {@inheritDoc} 258 * </p> 259 * 260 * @see org.xml.sax.ext.DefaultHandler2#endCDATA() 261 */ 262 @Override 263 public void endCDATA() throws SAXException { 264 stopIfCancelled(); 265 // Output CDATA built in characters() method 266 output.setProperty(path, DnaXmlLexicon.CDATA_CONTENT, cDataBuilder.toString()); 267 endElement(); 268 // Null-out builder to free memory 269 cDataBuilder = null; 270 updateProgress(); 271 } 272 273 private void endContent() { 274 if (contentBuilder != null) { 275 // Normalize content 276 String content = StringUtil.normalize(contentBuilder.toString()); 277 // Null-out builder to setup for subsequent content. 278 // Must be done before call to startElement below to prevent infinite loop. 279 contentBuilder = null; 280 // Skip if nothing in content but whitespace 281 if (content.length() > 0) { 282 // Create separate node for each content entry since entries can be interspersed amongst child elements 283 startElement(DnaXmlLexicon.ELEMENT_CONTENT); 284 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.ELEMENT_CONTENT); 285 output.setProperty(path, DnaXmlLexicon.ELEMENT_CONTENT, content); 286 endElement(); 287 } 288 } 289 } 290 291 /** 292 * <p> 293 * {@inheritDoc} 294 * </p> 295 * 296 * @see org.xml.sax.helpers.DefaultHandler#endDocument() 297 */ 298 @Override 299 public void endDocument() throws SAXException { 300 stopIfCancelled(); 301 } 302 303 /** 304 * <p> 305 * {@inheritDoc} 306 * </p> 307 * 308 * @see org.xml.sax.ext.DefaultHandler2#endDTD() 309 */ 310 @Override 311 public void endDTD() throws SAXException { 312 stopIfCancelled(); 313 } 314 315 private void endElement() { 316 // Recover parent's path, namespace, and indexedName map, clearing the ended element's map to free memory 317 path = path.getParent(); 318 nameToIndexedNamesMap.clear(); 319 nameToIndexedNamesMap = nameToIndexedNamesMapStack.removeFirst(); 320 nsStack.removeFirst(); 321 } 322 323 /** 324 * <p> 325 * {@inheritDoc} 326 * </p> 327 * 328 * @see org.xml.sax.helpers.DefaultHandler#endElement(java.lang.String, java.lang.String, java.lang.String) 329 */ 330 @Override 331 public void endElement( String uri, 332 String localName, 333 String name ) throws SAXException { 334 stopIfCancelled(); 335 // Check if content still needs to be output 336 endContent(); 337 endElement(); 338 updateProgress(); 339 } 340 341 /** 342 * <p> 343 * {@inheritDoc} 344 * </p> 345 * 346 * @see org.xml.sax.ext.DefaultHandler2#endEntity(java.lang.String) 347 */ 348 @Override 349 public void endEntity( String name ) throws SAXException { 350 stopIfCancelled(); 351 entity = null; 352 updateProgress(); 353 } 354 355 /** 356 * <p> 357 * {@inheritDoc} 358 * </p> 359 * 360 * @see org.xml.sax.helpers.DefaultHandler#error(org.xml.sax.SAXParseException) 361 */ 362 @Override 363 public void error( SAXParseException error ) { 364 context.getLogger(XmlSequencer.class).error(error, GraphI18n.errorSequencingXmlDocument, error); 365 monitor.getProblems().addError(error, GraphI18n.errorSequencingXmlDocument, error); 366 } 367 368 /** 369 * <p> 370 * {@inheritDoc} 371 * </p> 372 * 373 * @see org.xml.sax.ext.DefaultHandler2#externalEntityDecl(java.lang.String, java.lang.String, java.lang.String) 374 */ 375 @Override 376 public void externalEntityDecl( String name, 377 String publicId, 378 String systemId ) throws SAXException { 379 stopIfCancelled(); 380 // Add "synthetic" entity container to path to help prevent name collisions with XML elements 381 Name entityName = DnaDtdLexicon.ENTITY; 382 startElement(entityName); 383 output.setProperty(path, getPrimaryTypeName(), entityName); 384 output.setProperty(path, nameFactory.create(DnaDtdLexicon.NAME), name); 385 output.setProperty(path, nameFactory.create(DnaDtdLexicon.PUBLIC_ID), publicId); 386 output.setProperty(path, nameFactory.create(DnaDtdLexicon.SYSTEM_ID), systemId); 387 endElement(); 388 updateProgress(); 389 } 390 391 /** 392 * <p> 393 * {@inheritDoc} 394 * </p> 395 * 396 * @see org.xml.sax.helpers.DefaultHandler#fatalError(org.xml.sax.SAXParseException) 397 */ 398 @Override 399 public void fatalError( SAXParseException error ) { 400 context.getLogger(XmlSequencer.class).error(error, GraphI18n.fatalErrorSequencingXmlDocument, error); 401 monitor.getProblems().addError(error, GraphI18n.fatalErrorSequencingXmlDocument, error); 402 } 403 404 private Name getPrimaryTypeName() { 405 if (primaryTypeName == null) { 406 primaryTypeName = nameFactory.create(NameFactory.JCR_PRIMARY_TYPE); 407 } 408 return primaryTypeName; 409 } 410 411 private Name getDefaultPrimaryType() { 412 if (defaultPrimaryType == null) { 413 defaultPrimaryType = nameFactory.create(DEFAULT_PRIMARY_TYPE); 414 } 415 return defaultPrimaryType; 416 } 417 418 /** 419 * <p> 420 * {@inheritDoc} 421 * </p> 422 * 423 * @see org.xml.sax.helpers.DefaultHandler#ignorableWhitespace(char[], int, int) 424 */ 425 @Override 426 public void ignorableWhitespace( char[] ch, 427 int start, 428 int length ) throws SAXException { 429 stopIfCancelled(); 430 } 431 432 /** 433 * <p> 434 * {@inheritDoc} 435 * </p> 436 * 437 * @see org.xml.sax.ext.DefaultHandler2#internalEntityDecl(java.lang.String, java.lang.String) 438 */ 439 @Override 440 public void internalEntityDecl( String name, 441 String value ) throws SAXException { 442 stopIfCancelled(); 443 // Add "synthetic" entity container to path to help prevent name collisions with XML elements 444 Name entityName = DnaDtdLexicon.ENTITY; 445 startElement(entityName); 446 output.setProperty(path, getPrimaryTypeName(), entityName); 447 output.setProperty(path, DnaDtdLexicon.NAME, name); 448 output.setProperty(path, DnaDtdLexicon.VALUE, value); 449 endElement(); 450 updateProgress(); 451 } 452 453 /** 454 * <p> 455 * {@inheritDoc} 456 * </p> 457 * 458 * @see org.xml.sax.helpers.DefaultHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String) 459 */ 460 @Override 461 public void notationDecl( String name, 462 String publicId, 463 String systemId ) throws SAXException { 464 stopIfCancelled(); 465 } 466 467 /** 468 * <p> 469 * {@inheritDoc} 470 * </p> 471 * 472 * @see org.xml.sax.helpers.DefaultHandler#processingInstruction(java.lang.String, java.lang.String) 473 */ 474 @Override 475 public void processingInstruction( String target, 476 String data ) throws SAXException { 477 stopIfCancelled(); 478 // Output separate nodes for each instruction since multiple are allowed 479 Name name = DnaXmlLexicon.PROCESSING_INSTRUCTION; 480 startElement(name); 481 output.setProperty(path, getPrimaryTypeName(), name); 482 output.setProperty(path, DnaXmlLexicon.TARGET, target); 483 output.setProperty(path, DnaXmlLexicon.PROCESSING_INSTRUCTION_CONTENT, data); 484 endElement(); 485 updateProgress(); 486 } 487 488 /** 489 * <p> 490 * {@inheritDoc} 491 * </p> 492 * 493 * @see org.xml.sax.helpers.DefaultHandler#skippedEntity(java.lang.String) 494 */ 495 @Override 496 public void skippedEntity( String name ) throws SAXException { 497 stopIfCancelled(); 498 } 499 500 /** 501 * <p> 502 * {@inheritDoc} 503 * </p> 504 * 505 * @see org.xml.sax.ext.DefaultHandler2#startCDATA() 506 */ 507 @Override 508 public void startCDATA() throws SAXException { 509 stopIfCancelled(); 510 // Output separate nodes for each CDATA since multiple are allowed 511 startElement(DnaXmlLexicon.CDATA); 512 // Prepare builder for concatenating consecutive lines of CDATA 513 cDataBuilder = new StringBuilder(); 514 updateProgress(); 515 } 516 517 /** 518 * <p> 519 * {@inheritDoc} 520 * </p> 521 * 522 * @see org.xml.sax.helpers.DefaultHandler#startDocument() 523 */ 524 @Override 525 public void startDocument() throws SAXException { 526 stopIfCancelled(); 527 output.setProperty(path, getPrimaryTypeName(), DnaXmlLexicon.DOCUMENT); 528 updateProgress(); 529 } 530 531 /** 532 * <p> 533 * {@inheritDoc} 534 * </p> 535 * 536 * @see org.xml.sax.ext.DefaultHandler2#startDTD(java.lang.String, java.lang.String, java.lang.String) 537 */ 538 @Override 539 public void startDTD( String name, 540 String publicId, 541 String systemId ) throws SAXException { 542 stopIfCancelled(); 543 output.setProperty(path, DnaDtdLexicon.NAME, name); 544 output.setProperty(path, DnaDtdLexicon.PUBLIC_ID, publicId); 545 output.setProperty(path, DnaDtdLexicon.SYSTEM_ID, systemId); 546 updateProgress(); 547 } 548 549 private void startElement( Name name ) { 550 // Check if content still needs to be output 551 endContent(); 552 // Add name to list of indexed names for this element to ensure we use the correct index (which is the size of the 553 // list) 554 List<IndexedName> indexedNames = nameToIndexedNamesMap.get(name); 555 if (indexedNames == null) { 556 indexedNames = new ArrayList<IndexedName>(); 557 nameToIndexedNamesMap.put(name, indexedNames); 558 } 559 IndexedName indexedName = new IndexedName(); 560 indexedNames.add(indexedName); 561 // Add element name and the appropriate index to the path. 562 // Per the JCR spec, the index must be relative to same-name sibling nodes 563 path = context.getFactories().getPathFactory().create(path, name, indexedNames.size()); 564 path = path.getNormalizedPath(); 565 // Add the indexed name map to the stack and set the current map to the new element's map 566 nameToIndexedNamesMapStack.addFirst(nameToIndexedNamesMap); 567 nameToIndexedNamesMap = indexedName.nameToIndexedNamesMap; 568 // Set the current namespace to whatever is declared by this element, or if not declared, to its nearest ancestor that 569 // does declare a namespace. 570 String ns = name.getNamespaceUri(); 571 if (ns.length() == 0) { 572 nsStack.addFirst(nsStack.isEmpty() ? "" : nsStack.getFirst()); 573 } else { 574 nsStack.addFirst(ns); 575 } 576 } 577 578 /** 579 * <p> 580 * {@inheritDoc} 581 * </p> 582 * 583 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String, java.lang.String, java.lang.String, 584 * org.xml.sax.Attributes) 585 */ 586 @Override 587 public void startElement( String uri, 588 String localName, 589 String name, 590 Attributes attributes ) throws SAXException { 591 stopIfCancelled(); 592 // Look for the "jcr:name" attribute, and use that if it's there 593 Name type = getDefaultPrimaryType(); 594 Name nameObj = nameFactory.create(name); 595 for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) { 596 String ns = attributes.getURI(ndx); 597 String attrLocalName = attributes.getLocalName(ndx); 598 Object value = attributes.getValue(ndx); 599 String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr"); 600 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) { 601 nameObj = nameFactory.create(value); 602 break; 603 } 604 } 605 startElement(nameObj); 606 output.setProperty(path, getPrimaryTypeName(), type); 607 // Output this element's attributes using the attribute's namespace, if supplied, or the current namespace in scope. 608 String inheritedNs = nsStack.getFirst(); 609 for (int ndx = 0, len = attributes.getLength(); ndx < len; ++ndx) { 610 String ns = attributes.getURI(ndx); 611 String attrLocalName = attributes.getLocalName(ndx); 612 Object value = attributes.getValue(ndx); 613 String jcrNsUri = context.getNamespaceRegistry().getNamespaceForPrefix("jcr"); 614 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("primaryType")) { 615 value = nameFactory.create(value); 616 } 617 if (jcrNsUri != null && jcrNsUri.equals(ns) && attrLocalName.equals("name")) { 618 continue; 619 } 620 output.setProperty(path, nameFactory.create(ns.length() == 0 ? inheritedNs : ns, attrLocalName), value); 621 } 622 updateProgress(); 623 } 624 625 /** 626 * <p> 627 * {@inheritDoc} 628 * </p> 629 * 630 * @see org.xml.sax.ext.DefaultHandler2#startEntity(java.lang.String) 631 */ 632 @Override 633 public void startEntity( String name ) throws SAXException { 634 stopIfCancelled(); 635 entity = name; 636 updateProgress(); 637 } 638 639 /** 640 * <p> 641 * {@inheritDoc} 642 * </p> 643 * 644 * @see org.xml.sax.helpers.DefaultHandler#startPrefixMapping(java.lang.String, java.lang.String) 645 */ 646 @Override 647 public void startPrefixMapping( String prefix, 648 String uri ) throws SAXException { 649 stopIfCancelled(); 650 // Register any unregistered namespaces 651 NamespaceRegistry registry = context.getNamespaceRegistry(); 652 if (!registry.isRegisteredNamespaceUri(uri)) { 653 registry.register(prefix, uri); 654 } 655 updateProgress(); 656 } 657 658 private void stopIfCancelled() throws SAXException { 659 if (monitor.isCancelled()) { 660 throw new SAXException(GraphI18n.canceledSequencingXmlDocument.text()); 661 } 662 } 663 664 /** 665 * <p> 666 * {@inheritDoc} 667 * </p> 668 * 669 * @see org.xml.sax.helpers.DefaultHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, 670 * java.lang.String) 671 */ 672 @Override 673 public void unparsedEntityDecl( String name, 674 String publicId, 675 String systemId, 676 String notationName ) throws SAXException { 677 stopIfCancelled(); 678 } 679 680 private void updateProgress() { 681 if (progress == 100.0) { 682 progress = 1; 683 } else { 684 progress++; 685 } 686 monitor.worked(progress); 687 } 688 689 /** 690 * <p> 691 * {@inheritDoc} 692 * </p> 693 * 694 * @see org.xml.sax.helpers.DefaultHandler#warning(org.xml.sax.SAXParseException) 695 */ 696 @Override 697 public void warning( SAXParseException warning ) { 698 context.getLogger(XmlSequencer.class).warn(warning, GraphI18n.warningSequencingXmlDocument); 699 monitor.getProblems().addWarning(warning, GraphI18n.warningSequencingXmlDocument, warning); 700 } 701 } 702 703 private class IndexedName { 704 705 Map<Name, List<IndexedName>> nameToIndexedNamesMap = new HashMap<Name, List<IndexedName>>(); 706 707 IndexedName() { 708 } 709 } 710 }