Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » jaxp » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 2005 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *      http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   
   21   package com.sun.org.apache.xerces.internal.jaxp;
   22   
   23   import java.io.IOException;
   24   
   25   import javax.xml.validation.TypeInfoProvider;
   26   import javax.xml.validation.ValidatorHandler;
   27   
   28   import com.sun.org.apache.xerces.internal.dom.DOMInputImpl;
   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.xs.opti.DefaultXMLDocumentHandler;
   32   import com.sun.org.apache.xerces.internal.util.AttributesProxy;
   33   import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
   34   import com.sun.org.apache.xerces.internal.util.ErrorHandlerProxy;
   35   import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper;
   36   import com.sun.org.apache.xerces.internal.util.LocatorProxy;
   37   import com.sun.org.apache.xerces.internal.util.SymbolTable;
   38   import com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl;
   39   import com.sun.org.apache.xerces.internal.xni.Augmentations;
   40   import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
   41   import com.sun.org.apache.xerces.internal.xni.QName;
   42   import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
   43   import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
   44   import com.sun.org.apache.xerces.internal.xni.XMLLocator;
   45   import com.sun.org.apache.xerces.internal.xni.XMLString;
   46   import com.sun.org.apache.xerces.internal.xni.XNIException;
   47   import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
   48   import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
   49   import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
   50   import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
   51   import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler;
   52   import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
   53   import org.w3c.dom.TypeInfo;
   54   import org.w3c.dom.ls.LSInput;
   55   import org.w3c.dom.ls.LSResourceResolver;
   56   import org.xml.sax.Attributes;
   57   import org.xml.sax.ContentHandler;
   58   import org.xml.sax.ErrorHandler;
   59   import org.xml.sax.SAXException;
   60   import org.xml.sax.SAXParseException;
   61   import org.xml.sax.helpers.DefaultHandler;
   62   
   63   /**
   64    * Runs events through a {@link javax.xml.validation.ValidatorHandler}
   65    * and performs validation/infoset-augmentation by an external validator.
   66    *
   67    * <p>
   68    * This component sets up the pipeline as follows:
   69    *
   70    * <!-- this picture may look teribble on your IDE but it is correct. -->
   71    * <pre>
   72    *             __                                           __
   73    *            /  |==> XNI2SAX --> Validator --> SAX2XNI ==>|
   74    *           /   |                                         |
   75    *       ==>| Tee|                                         | next
   76    *           \   |                                         |  component
   77    *            \  |============other XNI events============>|
   78    *             ~~                                           ~~
   79    * </pre>
   80    * <p>
   81    * only those events that need to go through Validator will go the 1st route,
   82    * and other events go the 2nd direct route.
   83    *
   84    * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
   85    */
   86   final class JAXPValidatorComponent
   87       extends TeeXMLDocumentFilterImpl implements XMLComponent {
   88   
   89       /** Property identifier: entity manager. */
   90       private static final String ENTITY_MANAGER =
   91           Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
   92   
   93       /** Property identifier: error reporter. */
   94       private static final String ERROR_REPORTER =
   95           Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
   96   
   97       /** Property identifier: symbol table. */
   98       private static final String SYMBOL_TABLE =
   99           Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
  100   
  101       // pipeline parts
  102       private final ValidatorHandler validator;
  103       private final XNI2SAX xni2sax = new XNI2SAX();
  104       private final SAX2XNI sax2xni = new SAX2XNI();
  105   
  106       // never be null
  107       private final TypeInfoProvider typeInfoProvider;
  108   
  109       /**
  110        * Used to store the {@link Augmentations} associated with the
  111        * current event, so that we can pick it up again
  112        * when the event is forwarded by the {@link ValidatorHandler}.
  113        *
  114        * UGLY HACK.
  115        */
  116       private Augmentations fCurrentAug;
  117   
  118       /**
  119        * {@link XMLAttributes} version of {@link #fCurrentAug}.
  120        */
  121       private XMLAttributes fCurrentAttributes;
  122   
  123       // components obtained from a manager / property
  124   
  125       private SymbolTable fSymbolTable;
  126       private XMLErrorReporter fErrorReporter;
  127       private XMLEntityResolver fEntityResolver;
  128   
  129       /**
  130        * @param validatorHandler may not be null.
  131        */
  132       public JAXPValidatorComponent( ValidatorHandler validatorHandler ) {
  133           this.validator = validatorHandler;
  134           TypeInfoProvider tip = validatorHandler.getTypeInfoProvider();
  135           if(tip==null)   tip = noInfoProvider;
  136           this.typeInfoProvider = tip;
  137   
  138           // configure wiring between internal components.
  139           xni2sax.setContentHandler(validator);
  140           validator.setContentHandler(sax2xni);
  141           this.setSide(xni2sax);
  142   
  143           // configure validator with proper EntityResolver/ErrorHandler.
  144           validator.setErrorHandler(new ErrorHandlerProxy() {
  145               protected XMLErrorHandler getErrorHandler() {
  146                   XMLErrorHandler handler = fErrorReporter.getErrorHandler();
  147                   if(handler!=null)   return handler;
  148                   return new ErrorHandlerWrapper(DraconianErrorHandler.getInstance());
  149               }
  150           });
  151           validator.setResourceResolver(new LSResourceResolver() {
  152               public LSInput resolveResource(String type,String ns, String publicId, String systemId, String baseUri) {
  153                   if(fEntityResolver==null)   return null;
  154                   try {
  155                       XMLInputSource is = fEntityResolver.resolveEntity(
  156                           new XMLResourceIdentifierImpl(publicId,systemId,baseUri,null));
  157                       if(is==null)    return null;
  158   
  159                       LSInput di = new DOMInputImpl();
  160                       di.setBaseURI(is.getBaseSystemId());
  161                       di.setByteStream(is.getByteStream());
  162                       di.setCharacterStream(is.getCharacterStream());
  163                       di.setEncoding(is.getEncoding());
  164                       di.setPublicId(is.getPublicId());
  165                       di.setSystemId(is.getSystemId());
  166   
  167                       return di;
  168                   } catch( IOException e ) {
  169                       // erors thrown by the callback is not supposed to be
  170                       // reported to users.
  171                       throw new XNIException(e);
  172                   }
  173               }
  174           });
  175       }
  176   
  177   
  178       public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
  179           fCurrentAttributes = attributes;
  180           fCurrentAug = augs;
  181           xni2sax.startElement(element,attributes,null);
  182           fCurrentAttributes = null; // mostly to make it easy to find any bug.
  183       }
  184   
  185       public void endElement(QName element, Augmentations augs) throws XNIException {
  186           fCurrentAug = augs;
  187           xni2sax.endElement(element,null);
  188       }
  189   
  190       public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
  191           startElement(element,attributes,augs);
  192           endElement(element,augs);
  193       }
  194   
  195   
  196       public void characters(XMLString text, Augmentations augs) throws XNIException {
  197           // since a validator may change the contents,
  198           // let this one go through a validator
  199           fCurrentAug = augs;
  200           xni2sax.characters(text,null);
  201       }
  202   
  203       public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  204           // since a validator may change the contents,
  205           // let this one go through a validator
  206           fCurrentAug = augs;
  207           xni2sax.ignorableWhitespace(text,null);
  208       }
  209   
  210       public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
  211           // obtain references from the manager
  212           fSymbolTable = (SymbolTable)componentManager.getProperty(SYMBOL_TABLE);
  213           fErrorReporter = (XMLErrorReporter)componentManager.getProperty(ERROR_REPORTER);
  214           try {
  215               fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
  216           }
  217           catch (XMLConfigurationException e) {
  218               fEntityResolver = null;
  219           }
  220       }
  221   
  222       /**
  223        *
  224        * Uses {@link DefaultHandler} as a default implementation of
  225        * {@link ContentHandler}.
  226        *
  227        * <p>
  228        * We only forward certain events from a {@link ValidatorHandler}.
  229        * Other events should go "the 2nd direct route".
  230        */
  231       private final class SAX2XNI extends DefaultHandler {
  232   
  233           /**
  234            * {@link Augmentations} to send along with events.
  235            * We reuse one object for efficiency.
  236            */
  237           private final Augmentations fAugmentations = new AugmentationsImpl();
  238   
  239           /**
  240            * {@link QName} to send along events.
  241            * we reuse one QName for efficiency.
  242            */
  243           private final QName fQName = new QName();
  244   
  245           public void characters(char[] ch, int start, int len) throws SAXException {
  246               try {
  247                   handler().characters(new XMLString(ch,start,len),aug());
  248               } catch( XNIException e ) {
  249                   throw toSAXException(e);
  250               }
  251           }
  252   
  253           public void ignorableWhitespace(char[] ch, int start, int len) throws SAXException {
  254               try {
  255                   handler().ignorableWhitespace(new XMLString(ch,start,len),aug());
  256               } catch( XNIException e ) {
  257                   throw toSAXException(e);
  258               }
  259           }
  260   
  261           public void startElement(String uri, String localName, String qname, Attributes atts) throws SAXException {
  262               try {
  263                   updateAttributes(atts);
  264                   handler().startElement(toQName(uri,localName,qname), fCurrentAttributes, elementAug());
  265               } catch( XNIException e ) {
  266                   throw toSAXException(e);
  267               }
  268           }
  269   
  270           public void endElement(String uri, String localName, String qname) throws SAXException {
  271               try {
  272                   handler().endElement(toQName(uri,localName,qname),aug());
  273               } catch( XNIException e ) {
  274                   throw toSAXException(e);
  275               }
  276           }
  277   
  278           private Augmentations elementAug() {
  279               Augmentations aug = aug();
  280               /** aug.putItem(Constants.TYPEINFO,typeInfoProvider.getElementTypeInfo()); **/
  281               return aug;
  282           }
  283   
  284   
  285           /**
  286            * Gets the {@link Augmentations} that should be associated with
  287            * the current event.
  288            */
  289           private Augmentations aug() {
  290               if( fCurrentAug!=null ) {
  291                   Augmentations r = fCurrentAug;
  292                   fCurrentAug = null; // we "consumed" this augmentation.
  293                   return r;
  294               }
  295               fAugmentations.removeAllItems();
  296               return fAugmentations;
  297           }
  298   
  299           /**
  300            * Get the handler to which we should send events.
  301            */
  302           private XMLDocumentHandler handler() {
  303               return JAXPValidatorComponent.this.getDocumentHandler();
  304           }
  305   
  306           /**
  307            * Converts the {@link XNIException} received from a downstream
  308            * component to a {@link SAXException}.
  309            */
  310           private SAXException toSAXException( XNIException xe ) {
  311               Exception e = xe.getException();
  312               if( e==null )   e = xe;
  313               if( e instanceof SAXException )  return (SAXException)e;
  314               return new SAXException(e);
  315           }
  316   
  317           /**
  318            * Creates a proper {@link QName} object from 3 parts.
  319            * <p>
  320            * This method does the symbolization.
  321            */
  322           private QName toQName( String uri, String localName, String qname ) {
  323               String prefix = null;
  324               int idx = qname.indexOf(':');
  325               if( idx>0 )
  326                   prefix = symbolize(qname.substring(0,idx));
  327   
  328               localName = symbolize(localName);
  329               qname = symbolize(qname);
  330               uri = symbolize(uri);
  331   
  332               // notify handlers
  333               fQName.setValues(prefix, localName, qname, uri);
  334               return fQName;
  335           }
  336       }
  337   
  338       /**
  339        * Converts {@link XNI} events to {@link ContentHandler} events.
  340        *
  341        * <p>
  342        * Deriving from {@link DefaultXMLDocumentHandler}
  343        * to reuse its default {@link com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler}
  344        * implementation.
  345        *
  346        * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
  347        */
  348       private final class XNI2SAX extends DefaultXMLDocumentHandler {
  349   
  350           private ContentHandler fContentHandler;
  351   
  352           private String fVersion;
  353   
  354           /** Namespace context */
  355           protected NamespaceContext fNamespaceContext;
  356   
  357           /**
  358            * For efficiency, we reuse one instance.
  359            */
  360           private final AttributesProxy fAttributesProxy = new AttributesProxy(null);
  361   
  362           public void setContentHandler( ContentHandler handler ) {
  363               this.fContentHandler = handler;
  364           }
  365   
  366           public ContentHandler getContentHandler() {
  367               return fContentHandler;
  368           }
  369   
  370   
  371           public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) throws XNIException {
  372               this.fVersion = version;
  373           }
  374   
  375           public void startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs) throws XNIException {
  376               fNamespaceContext = namespaceContext;
  377               fContentHandler.setDocumentLocator(new LocatorProxy(locator));
  378               try {
  379                   fContentHandler.startDocument();
  380               } catch (SAXException e) {
  381                   throw new XNIException(e);
  382               }
  383           }
  384   
  385           public void endDocument(Augmentations augs) throws XNIException {
  386               try {
  387                   fContentHandler.endDocument();
  388               } catch (SAXException e) {
  389                   throw new XNIException(e);
  390               }
  391           }
  392   
  393           public void processingInstruction(String target, XMLString data, Augmentations augs) throws XNIException {
  394               try {
  395                   fContentHandler.processingInstruction(target,data.toString());
  396               } catch (SAXException e) {
  397                   throw new XNIException(e);
  398               }
  399           }
  400   
  401           public void startElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
  402               try {
  403                   // start namespace prefix mappings
  404                   int count = fNamespaceContext.getDeclaredPrefixCount();
  405                   if (count > 0) {
  406                       String prefix = null;
  407                       String uri = null;
  408                       for (int i = 0; i < count; i++) {
  409                           prefix = fNamespaceContext.getDeclaredPrefixAt(i);
  410                           uri = fNamespaceContext.getURI(prefix);
  411                           fContentHandler.startPrefixMapping(prefix, (uri == null)?"":uri);
  412                       }
  413                   }
  414   
  415                   String uri = element.uri != null ? element.uri : "";
  416                   String localpart = element.localpart;
  417                   fAttributesProxy.setAttributes(attributes);
  418                   fContentHandler.startElement(uri, localpart, element.rawname, fAttributesProxy);
  419               } catch( SAXException e ) {
  420                   throw new XNIException(e);
  421               }
  422           }
  423   
  424           public void endElement(QName element, Augmentations augs) throws XNIException {
  425               try {
  426                   String uri = element.uri != null ? element.uri : "";
  427                   String localpart = element.localpart;
  428                   fContentHandler.endElement(uri, localpart, element.rawname);
  429   
  430                   // send endPrefixMapping events
  431                   int count = fNamespaceContext.getDeclaredPrefixCount();
  432                   if (count > 0) {
  433                       for (int i = 0; i < count; i++) {
  434                           fContentHandler.endPrefixMapping(fNamespaceContext.getDeclaredPrefixAt(i));
  435                       }
  436                   }
  437               } catch( SAXException e ) {
  438                   throw new XNIException(e);
  439               }
  440           }
  441   
  442           public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
  443               startElement(element,attributes,augs);
  444               endElement(element,augs);
  445           }
  446   
  447           public void characters(XMLString text, Augmentations augs) throws XNIException {
  448               try {
  449                   fContentHandler.characters(text.ch,text.offset,text.length);
  450               } catch (SAXException e) {
  451                   throw new XNIException(e);
  452               }
  453           }
  454   
  455           public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
  456               try {
  457                   fContentHandler.ignorableWhitespace(text.ch,text.offset,text.length);
  458               } catch (SAXException e) {
  459                   throw new XNIException(e);
  460               }
  461           }
  462       }
  463   
  464       private static final class DraconianErrorHandler implements ErrorHandler {
  465   
  466           /**
  467            * Singleton instance.
  468            */
  469           private static final DraconianErrorHandler ERROR_HANDLER_INSTANCE
  470               = new DraconianErrorHandler();
  471   
  472           private DraconianErrorHandler() {}
  473   
  474           /** Returns the one and only instance of this error handler. */
  475           public static DraconianErrorHandler getInstance() {
  476               return ERROR_HANDLER_INSTANCE;
  477           }
  478   
  479           /** Warning: Ignore. */
  480           public void warning(SAXParseException e) throws SAXException {
  481               // noop
  482           }
  483   
  484           /** Error: Throws back SAXParseException. */
  485           public void error(SAXParseException e) throws SAXException {
  486               throw e;
  487           }
  488   
  489           /** Fatal Error: Throws back SAXParseException. */
  490           public void fatalError(SAXParseException e) throws SAXException {
  491               throw e;
  492           }
  493   
  494       } // DraconianErrorHandler
  495   
  496   
  497       /**
  498        * Compares the given {@link Attributes} with {@link #fCurrentAttributes}
  499        * and update the latter accordingly.
  500        */
  501       private void updateAttributes( Attributes atts ) {
  502           int len = atts.getLength();
  503           for( int i=0; i<len; i++ ) {
  504               String aqn = atts.getQName(i);
  505               int j = fCurrentAttributes.getIndex(aqn);
  506               String av = atts.getValue(i);
  507               if(j==-1) {
  508                   // newly added attribute. add to the current attribute list.
  509   
  510                   String prefix;
  511                   int idx = aqn.indexOf(':');
  512                   if( idx<0 ) {
  513                       prefix = null;
  514                   } else {
  515                       prefix = symbolize(aqn.substring(0,idx));
  516                   }
  517   
  518                   j = fCurrentAttributes.addAttribute(
  519                       new QName(
  520                           prefix,
  521                           symbolize(atts.getLocalName(i)),
  522                           symbolize(aqn),
  523                           symbolize(atts.getURI(i))),
  524                       atts.getType(i),av);
  525               } else {
  526                   // the attribute is present.
  527                   if( !av.equals(fCurrentAttributes.getValue(j)) ) {
  528                       // but the value was changed.
  529                       fCurrentAttributes.setValue(j,av);
  530                   }
  531               }
  532   
  533               /** Augmentations augs = fCurrentAttributes.getAugmentations(j);
  534               augs.putItem( Constants.TYPEINFO,
  535                   typeInfoProvider.getAttributeTypeInfo(i) );
  536               augs.putItem( Constants.ID_ATTRIBUTE,
  537                   typeInfoProvider.isIdAttribute(i)?Boolean.TRUE:Boolean.FALSE ); **/
  538           }
  539       }
  540   
  541       private String symbolize( String s ) {
  542           return fSymbolTable.addSymbol(s);
  543       }
  544   
  545   
  546       /**
  547        * {@link TypeInfoProvider} that returns no info.
  548        */
  549       private static final TypeInfoProvider noInfoProvider = new TypeInfoProvider() {
  550           public TypeInfo getElementTypeInfo() {
  551               return null;
  552           }
  553           public TypeInfo getAttributeTypeInfo(int index) {
  554               return null;
  555           }
  556           public TypeInfo getAttributeTypeInfo(String attributeQName) {
  557               return null;
  558           }
  559           public TypeInfo getAttributeTypeInfo(String attributeUri, String attributeLocalName) {
  560               return null;
  561           }
  562           public boolean isIdAttribute(int index) {
  563               return false;
  564           }
  565           public boolean isSpecified(int index) {
  566               return false;
  567           }
  568       };
  569   
  570       //
  571       //
  572       // XMLComponent implementation.
  573       //
  574       //
  575   
  576       // no property/feature supported
  577       public String[] getRecognizedFeatures() {
  578           return null;
  579       }
  580   
  581       public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
  582       }
  583   
  584       public String[] getRecognizedProperties() {
  585           return new String[]{ENTITY_MANAGER, ERROR_REPORTER, SYMBOL_TABLE};
  586       }
  587   
  588       public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
  589       }
  590   
  591       public Boolean getFeatureDefault(String featureId) {
  592           return null;
  593       }
  594   
  595       public Object getPropertyDefault(String propertyId) {
  596           return null;
  597       }
  598   
  599   }

Save This Page
Home » openjdk-7 » com.sun.org.apache.xerces.internal » jaxp » [javadoc | source]