1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.xerces.internal.xinclude; 23 24 25 import java.util.Enumeration; 26 import java.util.StringTokenizer; 27 import java.util.Stack; 28 29 import com.sun.org.apache.xerces.internal.impl.Constants; 30 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 31 import com.sun.org.apache.xerces.internal.impl.dtd.DTDGrammar; 32 import com.sun.org.apache.xerces.internal.util.ParserConfigurationSettings; 33 import com.sun.org.apache.xerces.internal.xni.Augmentations; 34 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 35 import com.sun.org.apache.xerces.internal.xni.QName; 36 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 37 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 38 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 39 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 40 import com.sun.org.apache.xerces.internal.xni.XMLString; 41 import com.sun.org.apache.xerces.internal.xni.XNIException; 42 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 43 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 44 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 45 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 46 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 47 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; 48 import com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator; 49 /** 50 * @author Arun Yadav, Sun Microsystem 51 */ 52 public class XPointerElementHandler implements XPointerSchema { 53 54 55 // recognized features and properties 56 57 /** Property identifier: error handler. */ 58 protected static final String ERROR_REPORTER = 59 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 60 61 /** Property identifier: grammar pool . */ 62 protected static final String GRAMMAR_POOL = 63 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 64 65 /** Property identifier: grammar pool . */ 66 protected static final String ENTITY_RESOLVER = 67 Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY; 68 69 protected static final String XPOINTER_SCHEMA = 70 Constants.XERCES_PROPERTY_PREFIX + Constants.XPOINTER_SCHEMA_PROPERTY; 71 72 /** Recognized features. */ 73 private static final String[] RECOGNIZED_FEATURES = { 74 }; 75 76 /** Feature defaults. */ 77 private static final Boolean[] FEATURE_DEFAULTS = { 78 }; 79 80 /** Recognized properties. */ 81 82 private static final String[] RECOGNIZED_PROPERTIES = 83 { ERROR_REPORTER, GRAMMAR_POOL, ENTITY_RESOLVER, XPOINTER_SCHEMA }; 84 85 /** Property defaults. */ 86 private static final Object[] PROPERTY_DEFAULTS = { null, null, null,null }; 87 88 // Data 89 90 protected XMLDocumentHandler fDocumentHandler; 91 protected XMLDocumentSource fDocumentSource; 92 93 protected XIncludeHandler fParentXIncludeHandler; 94 95 protected XMLLocator fDocLocation; 96 protected XIncludeNamespaceSupport fNamespaceContext; 97 protected XMLErrorReporter fErrorReporter; 98 protected XMLGrammarPool fGrammarPool; 99 protected XMLGrammarDescription fGrammarDesc; 100 protected DTDGrammar fDTDGrammar; 101 protected XMLEntityResolver fEntityResolver; 102 protected ParserConfigurationSettings fSettings; 103 //protected String fPointerSchema; 104 protected StringBuffer fPointer; 105 private int elemCount = 0; 106 107 108 // The current element depth. 109 // This is used to access the appropriate level of the following stacks. 110 private int fDepth; 111 112 // The depth of the first element to actually be part of the result infoset. 113 // This will normally be 1, but it could be larger when the top-level item 114 // is an include, and processing goes to the fallback. 115 private int fRootDepth; 116 117 // this value must be at least 1 118 private static final int INITIAL_SIZE = 8; 119 120 121 // Used to ensure that fallbacks are always children of include elements, 122 // and that include elements are never children of other include elements. 123 // An index contains true if the ancestor of the current element which resides 124 // at that depth was an include element. 125 private boolean[] fSawInclude = new boolean[INITIAL_SIZE]; 126 127 128 // Ensures that only one fallback element can be at a single depth. 129 // An index contains true if we have seen any fallback elements at that depth, 130 // and it is only reset to false when the end tag of the parent is encountered. 131 private boolean[] fSawFallback = new boolean[INITIAL_SIZE]; 132 133 134 // The state of the processor at each given depth. 135 private int[] fState = new int[INITIAL_SIZE]; 136 137 QName foundElement = null; 138 boolean skip = false; 139 // Constructors 140 141 public XPointerElementHandler() { 142 143 144 fDepth = 0; 145 fRootDepth = 0; 146 fSawFallback[fDepth] = false; 147 fSawInclude[fDepth] = false; 148 fSchemaName="element"; 149 150 151 } 152 153 // START OF IMPLEMENTATION OF XMLComponent methods ////// 154 155 public void reset(){ 156 elemCount =0; 157 fPointerToken = null; 158 fCurrentTokenint=0; 159 fCurrentTokenString=null; 160 fCurrentTokenType=0 ; 161 fElementCount =0; 162 fCurrentToken =0; 163 includeElement = false; 164 foundElement = null; 165 skip = false; 166 fSubResourceIdentified=false; 167 } 168 169 public void reset(XMLComponentManager componentManager) 170 throws XNIException { 171 fNamespaceContext = null; 172 elemCount =0; 173 fDepth = 0; 174 fRootDepth = 0; 175 fPointerToken = null; 176 fCurrentTokenint=0; 177 fCurrentTokenString=null; 178 fCurrentTokenType=0 ; 179 foundElement = null; 180 includeElement = false; 181 skip = false; 182 fSubResourceIdentified=false; 183 184 185 186 187 try { 188 setErrorReporter( 189 (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER)); 190 } 191 catch (XMLConfigurationException e) { 192 fErrorReporter = null; 193 } 194 try { 195 fGrammarPool = 196 (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL); 197 } 198 catch (XMLConfigurationException e) { 199 fGrammarPool = null; 200 } 201 try { 202 fEntityResolver = 203 (XMLEntityResolver)componentManager.getProperty( 204 ENTITY_RESOLVER); 205 } 206 catch (XMLConfigurationException e) { 207 fEntityResolver = null; 208 } 209 210 fSettings = new ParserConfigurationSettings(); 211 212 Enumeration xercesFeatures = Constants.getXercesFeatures(); 213 while (xercesFeatures.hasMoreElements()) { 214 String featureId = (String)xercesFeatures.nextElement(); 215 fSettings.addRecognizedFeatures(new String[] { featureId }); 216 try { 217 fSettings.setFeature( 218 featureId, 219 componentManager.getFeature(featureId)); 220 } 221 catch (XMLConfigurationException e) { 222 // componentManager doesn't support this feature, 223 // so we won't worry about it 224 } 225 } 226 /* try{ 227 dtdValidator = (XMLDTDValidator)componentManager.getProperty( Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY); 228 }Catch(Exception ex){ 229 ex.printStackTrace(); 230 }*/ 231 232 } // reset(XMLComponentManager) 233 234 /** 235 * Returns a list of feature identifiers that are recognized by 236 * this component. This method may return null if no features 237 * are recognized by this component. 238 */ 239 public String[] getRecognizedFeatures() { 240 return RECOGNIZED_FEATURES; 241 } // getRecognizedFeatures():String[] 242 243 /** 244 * Sets the state of a feature. This method is called by the component 245 * manager any time after reset when a feature changes state. 246 * <p> 247 * <strong>Note:</strong> Components should silently ignore features 248 * that do not affect the operation of the component. 249 * 250 * @param featureId The feature identifier. 251 * @param state The state of the feature. 252 * 253 * @throws SAXNotRecognizedException The component should not throw 254 * this exception. 255 * @throws SAXNotSupportedException The component should not throw 256 * this exception. 257 */ 258 public void setFeature(String featureId, boolean state) 259 throws XMLConfigurationException { 260 if (fSettings != null) { 261 fSettings.setFeature(featureId, state); 262 } 263 264 } // setFeature(String,boolean) 265 266 /** 267 * Returns a list of property identifiers that are recognized by 268 * this component. This method may return null if no properties 269 * are recognized by this component. 270 */ 271 public String[] getRecognizedProperties() { 272 return RECOGNIZED_PROPERTIES; 273 } // getRecognizedProperties():String[] 274 275 /** 276 * Sets the value of a property. This method is called by the component 277 * manager any time after reset when a property changes value. 278 * <p> 279 * <strong>Note:</strong> Components should silently ignore properties 280 * that do not affect the operation of the component. 281 * 282 * @param propertyId The property identifier. 283 * @param value The value of the property. 284 * 285 * @throws SAXNotRecognizedException The component should not throw 286 * this exception. 287 * @throws SAXNotSupportedException The component should not throw 288 * this exception. 289 */ 290 public void setProperty(String propertyId, Object value) 291 throws XMLConfigurationException { 292 if (propertyId.equals(ERROR_REPORTER)) { 293 setErrorReporter((XMLErrorReporter)value); 294 } 295 if (propertyId.equals(GRAMMAR_POOL)) { 296 fGrammarPool = (XMLGrammarPool)value; 297 } 298 if (propertyId.equals(ENTITY_RESOLVER)) { 299 fEntityResolver = (XMLEntityResolver)value; 300 } 301 302 } // setProperty(String,Object) 303 304 /** 305 * Returns the default state for a feature, or null if this 306 * component does not want to report a default value for this 307 * feature. 308 * 309 * @param featureId The feature identifier. 310 * 311 * @since Xerces 2.2.0 312 */ 313 public Boolean getFeatureDefault(String featureId) { 314 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 315 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 316 return FEATURE_DEFAULTS[i]; 317 } 318 } 319 return null; 320 } // getFeatureDefault(String):Boolean 321 322 /** 323 * Returns the default state for a property, or null if this 324 * component does not want to report a default value for this 325 * property. 326 * 327 * @param propertyId The property identifier. 328 * 329 * @since Xerces 2.2.0 330 */ 331 public Object getPropertyDefault(String propertyId) { 332 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 333 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 334 return PROPERTY_DEFAULTS[i]; 335 } 336 } 337 return null; 338 } // getPropertyDefault(String):Object 339 340 private void setErrorReporter(XMLErrorReporter reporter) { 341 fErrorReporter = reporter; 342 if (fErrorReporter != null) { 343 fErrorReporter.putMessageFormatter( 344 XIncludeMessageFormatter.XINCLUDE_DOMAIN, 345 new XIncludeMessageFormatter()); 346 } 347 } 348 ///////// END OF IMPLEMENTATION OF XMLComponents methods. ////////// 349 350 351 352 //////// START OF IMPLEMENTATION OF XMLDOCUMENTSOURCE INTERFACE ///////// 353 354 public void setDocumentHandler(XMLDocumentHandler handler) { 355 fDocumentHandler = handler; 356 } 357 358 public XMLDocumentHandler getDocumentHandler() { 359 return fDocumentHandler; 360 } 361 362 /////// END OF IMPLENTATION OF XMLDOCUMENTSOURCE INTERFACE /////////// 363 364 365 366 367 /////////////// Implementation of XPointerSchema Methods ////////////////////// 368 369 String fSchemaName; 370 String fSchemaPointer; 371 boolean fSubResourceIdentified; 372 /** 373 * set the Schema Name eg element , xpointer 374 */ 375 public void setXPointerSchemaName(String schemaName){ 376 fSchemaName = schemaName; 377 } 378 379 /** 380 * Return Schema Name eg element , xpointer 381 * 382 */ 383 public String getXpointerSchemaName(){ 384 return fSchemaName; 385 } 386 387 /** 388 * Parent Contenhandler for the this contenthandler. 389 * // not sure about the parameter type. It can be Contenthandler instead of Object type. 390 */ 391 public void setParent(Object parent){ 392 fParentXIncludeHandler = (XIncludeHandler)parent; 393 } 394 395 396 /** 397 * return the Parent Contenthandler 398 */ 399 public Object getParent(){ 400 return fParentXIncludeHandler; 401 } 402 403 /** 404 * Content of the XPointer Schema. Xpath to be resolved. 405 */ 406 public void setXPointerSchemaPointer(String content){ 407 fSchemaPointer = content; 408 } 409 410 /** 411 * Return the XPointer Schema. 412 */ 413 public String getXPointerSchemaPointer(){ 414 return fSchemaPointer; 415 } 416 417 public boolean isSubResourceIndentified(){ 418 return fSubResourceIdentified; 419 } 420 421 ///////////End Implementation of XPointerSchema Methods ////////////////////// 422 423 424 425 //////////// Tokens Playground /////////////////// 426 427 Stack fPointerToken = new Stack(); 428 int fCurrentTokenint=0; 429 String fCurrentTokenString=null; 430 int fCurrentTokenType=0 ;// 0 Notype; 1 for integer; 2 for string. 431 432 public void getTokens(){ 433 fSchemaPointer = fSchemaPointer.substring(fSchemaPointer.indexOf("(")+1, fSchemaPointer.length()); 434 StringTokenizer st = new StringTokenizer(fSchemaPointer, "/"); 435 String tempToken; 436 Integer integerToken =null; 437 Stack tempPointerToken = new Stack(); 438 if(fPointerToken == null){ 439 fPointerToken = new Stack(); 440 } 441 while(st.hasMoreTokens()){ 442 tempToken=st.nextToken(); 443 try { 444 integerToken = Integer.valueOf(tempToken); 445 tempPointerToken.push(integerToken); 446 }catch(NumberFormatException e){ 447 tempPointerToken.push(tempToken); 448 } 449 } 450 while(!tempPointerToken.empty()){ 451 fPointerToken.push(tempPointerToken.pop()); 452 } 453 }//getTokens 454 455 456 public boolean hasMoreToken(){ 457 if(fPointerToken.isEmpty()) 458 return false; 459 else 460 return true; 461 } 462 463 public boolean getNextToken(){ 464 Object currentToken; 465 if (!fPointerToken.isEmpty()){ 466 currentToken = fPointerToken.pop(); 467 if(currentToken instanceof Integer){ 468 fCurrentTokenint = ((Integer)currentToken).intValue(); 469 fCurrentTokenType = 1; 470 } 471 else{ 472 fCurrentTokenString = ((String)currentToken).toString(); 473 fCurrentTokenType = 2; 474 } 475 return true; 476 } 477 else { 478 return false; 479 } 480 } 481 482 private boolean isIdAttribute(XMLAttributes attributes,Augmentations augs, int index) { 483 Object o = augs.getItem(Constants.ID_ATTRIBUTE); 484 if( o instanceof Boolean ) 485 return ((Boolean)o).booleanValue(); 486 return "ID".equals(attributes.getType(index)); 487 } 488 489 public boolean checkStringToken(QName element, XMLAttributes attributes){ 490 QName cacheQName = null; 491 String id =null; 492 String rawname =null; 493 QName attrName = new QName(); 494 String attrType = null; 495 String attrValue = null; 496 int attrCount = attributes.getLength(); 497 for (int i = 0; i < attrCount; i++) { 498 Augmentations aaugs = attributes.getAugmentations(i); 499 attributes.getName(i,attrName); 500 attrType = attributes.getType(i); 501 attrValue = attributes.getValue(i); 502 if(attrType != null && attrValue!= null && isIdAttribute(attributes,aaugs,i) && attrValue.equals(fCurrentTokenString)){ 503 if(hasMoreToken()){ 504 fCurrentTokenType = 0; 505 fCurrentTokenString = null; 506 return true; 507 } 508 else{ 509 foundElement = element; 510 includeElement = true; 511 fCurrentTokenType = 0; 512 fCurrentTokenString = null; 513 fSubResourceIdentified = true; 514 return true; 515 } 516 } 517 } 518 return false; 519 } 520 521 public boolean checkIntegerToken(QName element){ 522 if(!skip){ 523 fElementCount++; 524 if(fCurrentTokenint == fElementCount){ 525 if(hasMoreToken()){ 526 fElementCount=0; 527 fCurrentTokenType = 0; 528 return true; 529 } 530 else{ 531 foundElement = element; 532 includeElement = true; 533 fCurrentTokenType = 0; 534 fElementCount=0; 535 fSubResourceIdentified =true; 536 return true; 537 } 538 }else{ 539 addQName(element); 540 skip = true; 541 return false; 542 } 543 } 544 return false; 545 } 546 547 public void addQName(QName element){ 548 QName cacheQName = new QName(element); 549 ftempCurrentElement.push(cacheQName); 550 } 551 552 /////////// END TOKEN PLAYGROUND /////////////// 553 554 555 ///// START OF IMPLEMTATION OF XMLDocumentHandler methods ////////// 556 557 558 public void startDocument(XMLLocator locator, String encoding, 559 NamespaceContext namespaceContext, Augmentations augs) 560 throws XNIException { 561 562 getTokens(); 563 } 564 565 public void doctypeDecl(String rootElement, String publicId, String systemId, 566 Augmentations augs)throws XNIException { 567 } 568 569 public void xmlDecl(String version, String encoding, String standalone, 570 Augmentations augs) throws XNIException { 571 } 572 573 574 public void comment(XMLString text, Augmentations augs) 575 throws XNIException { 576 if (fDocumentHandler != null && includeElement) { 577 fDocumentHandler.comment(text, augs); 578 } 579 } 580 581 public void processingInstruction(String target, XMLString data, 582 Augmentations augs) throws XNIException { 583 if (fDocumentHandler != null && includeElement) { 584 fDocumentHandler.processingInstruction(target, data, augs); 585 586 } 587 } 588 589 Stack ftempCurrentElement = new Stack(); 590 int fElementCount =0; 591 int fCurrentToken ; 592 boolean includeElement; 593 594 595 public void startElement(QName element, XMLAttributes attributes, 596 Augmentations augs)throws XNIException { 597 598 boolean requiredToken=false; 599 if(fCurrentTokenType == 0) 600 getNextToken(); 601 if(fCurrentTokenType ==1) 602 requiredToken = checkIntegerToken(element); 603 else if (fCurrentTokenType ==2) 604 requiredToken = checkStringToken(element, attributes); 605 if(requiredToken && hasMoreToken()) 606 getNextToken(); 607 if(fDocumentHandler != null && includeElement){ 608 elemCount++; 609 fDocumentHandler.startElement(element, attributes, augs); 610 } 611 612 } 613 614 615 public void endElement(QName element, Augmentations augs) 616 throws XNIException { 617 if(includeElement && foundElement != null ){ 618 if(elemCount >0 )elemCount --; 619 fDocumentHandler.endElement(element, augs); 620 if(elemCount == 0)includeElement = false; 621 622 }else if(!ftempCurrentElement.empty()){ 623 QName name = (QName)ftempCurrentElement.peek(); 624 if(name.equals(element)){ 625 ftempCurrentElement.pop(); 626 skip = false; 627 } 628 } 629 } 630 631 public void emptyElement(QName element, XMLAttributes attributes, 632 Augmentations augs)throws XNIException { 633 if(fDocumentHandler != null && includeElement){ 634 fDocumentHandler.emptyElement(element, attributes, augs); 635 } 636 } 637 638 public void startGeneralEntity(String name, XMLResourceIdentifier resId, 639 String encoding, 640 Augmentations augs) 641 throws XNIException { 642 if (fDocumentHandler != null && includeElement) { 643 fDocumentHandler.startGeneralEntity(name, resId, encoding, augs); 644 } 645 } 646 647 public void textDecl(String version, String encoding, Augmentations augs) 648 throws XNIException { 649 if (fDocumentHandler != null && includeElement) { 650 fDocumentHandler.textDecl(version, encoding, augs); 651 } 652 } 653 654 public void endGeneralEntity(String name, Augmentations augs) 655 throws XNIException { 656 if (fDocumentHandler != null) { 657 fDocumentHandler.endGeneralEntity(name, augs); 658 } 659 } 660 661 public void characters(XMLString text, Augmentations augs) 662 throws XNIException { 663 if (fDocumentHandler != null && includeElement) { 664 fDocumentHandler.characters(text, augs); 665 } 666 } 667 668 public void ignorableWhitespace(XMLString text, Augmentations augs) 669 throws XNIException { 670 if (fDocumentHandler != null && includeElement) { 671 fDocumentHandler.ignorableWhitespace(text, augs); 672 } 673 } 674 675 public void startCDATA(Augmentations augs) throws XNIException { 676 if (fDocumentHandler != null && includeElement) { 677 fDocumentHandler.startCDATA(augs); 678 } 679 } 680 681 public void endCDATA(Augmentations augs) throws XNIException { 682 if (fDocumentHandler != null && includeElement) { 683 fDocumentHandler.endCDATA(augs); 684 } 685 } 686 687 public void endDocument(Augmentations augs) throws XNIException { 688 } 689 690 public void setDocumentSource(XMLDocumentSource source) { 691 fDocumentSource = source; 692 } 693 694 public XMLDocumentSource getDocumentSource() { 695 return fDocumentSource; 696 } 697 698 699 protected void reportFatalError(String key) { 700 this.reportFatalError(key, null); 701 } 702 703 protected void reportFatalError(String key, Object[] args) { 704 if (fErrorReporter != null) { 705 fErrorReporter.reportError( 706 fDocLocation, 707 XIncludeMessageFormatter.XINCLUDE_DOMAIN, 708 key, 709 args, 710 XMLErrorReporter.SEVERITY_FATAL_ERROR); 711 } 712 // we won't worry about when error reporter is null, since there should always be 713 // at least the default error reporter 714 } 715 716 717 718 // used to know whether to pass declarations to the document handler 719 protected boolean isRootDocument() { 720 return this.fParentXIncludeHandler == null; 721 } 722 723 724 } // class XPointerElementhandler