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 package com.sun.org.apache.xerces.internal.dom;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  24 import com.sun.org.apache.xerces.internal.parsers.DOMParserImpl;
  25 import com.sun.org.apache.xerces.internal.parsers.DTDConfiguration;
  26 import com.sun.org.apache.xerces.internal.parsers.XIncludeAwareParserConfiguration;
  27 import com.sun.org.apache.xerces.internal.util.XMLChar;
  28 import com.sun.org.apache.xerces.internal.utils.ObjectFactory;
  29 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  30 import com.sun.org.apache.xml.internal.serialize.DOMSerializerImpl;
  31 import org.w3c.dom.DOMException;
  32 import org.w3c.dom.DOMImplementation;
  33 import org.w3c.dom.Document;
  34 import org.w3c.dom.DocumentType;
  35 import org.w3c.dom.Element;
  36 import org.w3c.dom.ls.LSParser;
  37 import org.w3c.dom.ls.DOMImplementationLS;
  38 import org.w3c.dom.ls.LSInput;
  39 import org.w3c.dom.ls.LSOutput;
  40 import org.w3c.dom.ls.LSSerializer;
  41 /**
  42  * The DOMImplementation class is description of a particular
  43  * implementation of the Document Object Model. As such its data is
  44  * static, shared by all instances of this implementation.
  45  * <P>
  46  * The DOM API requires that it be a real object rather than static
  47  * methods. However, there's nothing that says it can't be a singleton,
  48  * so that's how I've implemented it.
  49  * <P>
  50  * This particular class, along with CoreDocumentImpl, supports the DOM
  51  * Core and Load/Save (Experimental). Optional modules are supported by
  52  * the more complete DOMImplementation class along with DocumentImpl.
  53  *
  54  * @xerces.internal
  55  *
  56  * @since PR-DOM-Level-1-19980818.
  57  */
  58 public class CoreDOMImplementationImpl
  59         implements DOMImplementation, DOMImplementationLS {
  60         //
  61         // Data
  62         //
  63 
  64     // validators pool
  65     private static final int SIZE = 2;
  66     private RevalidationHandler validators[] = new RevalidationHandler[SIZE];
  67 
  68     private RevalidationHandler dtdValidators[] = new RevalidationHandler[SIZE];
  69     private int freeValidatorIndex = -1;
  70     private int freeDTDValidatorIndex = -1;
  71     private int currentSize = SIZE;
  72 
  73     // Document and doctype counter.  Used to assign order to documents and
  74     // doctypes without owners, on an demand basis.   Used for
  75     // compareDocumentPosition
  76     private int docAndDoctypeCounter = 0;
  77 
  78         // static
  79         /** Dom implementation singleton. */
  80         static CoreDOMImplementationImpl singleton =
  81                 new CoreDOMImplementationImpl();
  82         //
  83         // Public methods
  84         //
  85         /** NON-DOM: Obtain and return the single shared object */
  86         public static DOMImplementation getDOMImplementation() {
  87                 return singleton;
  88         }
  89         //
  90         // DOMImplementation methods
  91         //
  92         /**
  93          * Test if the DOM implementation supports a specific "feature" --
  94          * currently meaning language and level thereof.
  95          *
  96          * @param feature The package name of the feature to test.
  97          * In Level 1, supported values are "HTML" and "XML" (case-insensitive).
  98          * At this writing, com.sun.org.apache.xerces.internal.dom supports only XML.
  99          *
 100          * @param version The version number of the feature being tested.
 101          * This is interpreted as "Version of the DOM API supported for the
 102          * specified Feature", and in Level 1 should be "1.0"
 103          *
 104          * @return true iff this implementation is compatable with the specified
 105          * feature and version.
 106          */
 107         public boolean hasFeature(String feature, String version) {
 108 
 109             boolean anyVersion = version == null || version.length() == 0;
 110 
 111             if (feature.startsWith("+")) {
 112                 feature = feature.substring(1);
 113             }
 114             return (
 115                 feature.equalsIgnoreCase("Core")
 116                     && (anyVersion
 117                         || version.equals("1.0")
 118                         || version.equals("2.0")
 119                         || version.equals("3.0")))
 120                         || (feature.equalsIgnoreCase("XML")
 121                     && (anyVersion
 122                         || version.equals("1.0")
 123                         || version.equals("2.0")
 124                         || version.equals("3.0")))
 125                         || (feature.equalsIgnoreCase("LS")
 126                     && (anyVersion || version.equals("3.0")));
 127         } // hasFeature(String,String):boolean
 128 
 129 
 130         /**
 131          * Introduced in DOM Level 2. <p>
 132          *
 133          * Creates an empty DocumentType node.
 134          *
 135          * @param qualifiedName The qualified name of the document type to be created.
 136          * @param publicID The document type public identifier.
 137          * @param systemID The document type system identifier.
 138          * @since WD-DOM-Level-2-19990923
 139          */
 140         public DocumentType createDocumentType( String qualifiedName,
 141                                     String publicID, String systemID) {
 142                 // REVISIT: this might allow creation of invalid name for DOCTYPE
 143                 //          xmlns prefix.
 144                 //          also there is no way for a user to turn off error checking.
 145                 checkQName(qualifiedName);
 146                 return new DocumentTypeImpl(null, qualifiedName, publicID, systemID);
 147         }
 148 
 149     final void checkQName(String qname){
 150         int index = qname.indexOf(':');
 151         int lastIndex = qname.lastIndexOf(':');
 152         int length = qname.length();
 153 
 154         // it is an error for NCName to have more than one ':'
 155         // check if it is valid QName [Namespace in XML production 6]
 156         if (index == 0 || index == length - 1 || lastIndex != index) {
 157             String msg =
 158                 DOMMessageFormatter.formatMessage(
 159                     DOMMessageFormatter.DOM_DOMAIN,
 160                     "NAMESPACE_ERR",
 161                     null);
 162             throw new DOMException(DOMException.NAMESPACE_ERR, msg);
 163         }
 164         int start = 0;
 165         // Namespace in XML production [6]
 166         if (index > 0) {
 167             // check that prefix is NCName
 168             if (!XMLChar.isNCNameStart(qname.charAt(start))) {
 169                 String msg =
 170                     DOMMessageFormatter.formatMessage(
 171                         DOMMessageFormatter.DOM_DOMAIN,
 172                         "INVALID_CHARACTER_ERR",
 173                         null);
 174                 throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 175             }
 176             for (int i = 1; i < index; i++) {
 177                 if (!XMLChar.isNCName(qname.charAt(i))) {
 178                     String msg =
 179                         DOMMessageFormatter.formatMessage(
 180                             DOMMessageFormatter.DOM_DOMAIN,
 181                             "INVALID_CHARACTER_ERR",
 182                             null);
 183                     throw new DOMException(
 184                         DOMException.INVALID_CHARACTER_ERR,
 185                         msg);
 186                 }
 187             }
 188             start = index + 1;
 189         }
 190 
 191         // check local part
 192         if (!XMLChar.isNCNameStart(qname.charAt(start))) {
 193             // REVISIT: add qname parameter to the message
 194             String msg =
 195                 DOMMessageFormatter.formatMessage(
 196                     DOMMessageFormatter.DOM_DOMAIN,
 197                     "INVALID_CHARACTER_ERR",
 198                     null);
 199             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 200         }
 201         for (int i = start + 1; i < length; i++) {
 202             if (!XMLChar.isNCName(qname.charAt(i))) {
 203                 String msg =
 204                     DOMMessageFormatter.formatMessage(
 205                         DOMMessageFormatter.DOM_DOMAIN,
 206                         "INVALID_CHARACTER_ERR",
 207                         null);
 208                 throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 209             }
 210         }
 211     }
 212 
 213 
 214         /**
 215          * Introduced in DOM Level 2. <p>
 216          *
 217          * Creates an XML Document object of the specified type with its document
 218          * element.
 219          *
 220          * @param namespaceURI     The namespace URI of the document
 221          *                         element to create, or null.
 222          * @param qualifiedName    The qualified name of the document
 223          *                         element to create.
 224          * @param doctype          The type of document to be created or null.<p>
 225          *
 226          *                         When doctype is not null, its
 227          *                         Node.ownerDocument attribute is set to
 228          *                         the document being created.
 229          * @return Document        A new Document object.
 230          * @throws DOMException    WRONG_DOCUMENT_ERR: Raised if doctype has
 231          *                         already been used with a different document.
 232          * @since WD-DOM-Level-2-19990923
 233          */
 234         public Document createDocument(
 235                 String namespaceURI,
 236                 String qualifiedName,
 237                 DocumentType doctype)
 238                 throws DOMException {
 239                 if (doctype != null && doctype.getOwnerDocument() != null) {
 240                         String msg =
 241                                 DOMMessageFormatter.formatMessage(
 242                                         DOMMessageFormatter.DOM_DOMAIN,
 243                                         "WRONG_DOCUMENT_ERR",
 244                                         null);
 245                         throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
 246                 }
 247                 CoreDocumentImpl doc = new CoreDocumentImpl(doctype);
 248                 Element e = doc.createElementNS(namespaceURI, qualifiedName);
 249                 doc.appendChild(e);
 250                 return doc;
 251         }
 252 
 253         /**
 254          * DOM Level 3 WD - Experimental.
 255          */
 256         public Object getFeature(String feature, String version) {
 257             if (singleton.hasFeature(feature, version)) {
 258                 return singleton;
 259             }
 260             return null;
 261         }
 262 
 263         // DOM L3 LS
 264 
 265         /**
 266          * DOM Level 3 LS CR - Experimental.
 267      * Create a new <code>LSParser</code>. The newly constructed parser may
 268      * then be configured by means of its <code>DOMConfiguration</code>
 269      * object, and used to parse documents by means of its <code>parse</code>
 270      *  method.
 271      * @param mode  The <code>mode</code> argument is either
 272      *   <code>MODE_SYNCHRONOUS</code> or <code>MODE_ASYNCHRONOUS</code>, if
 273      *   <code>mode</code> is <code>MODE_SYNCHRONOUS</code> then the
 274      *   <code>LSParser</code> that is created will operate in synchronous
 275      *   mode, if it's <code>MODE_ASYNCHRONOUS</code> then the
 276      *   <code>LSParser</code> that is created will operate in asynchronous
 277      *   mode.
 278      * @param schemaType  An absolute URI representing the type of the schema
 279      *   language used during the load of a <code>Document</code> using the
 280      *   newly created <code>LSParser</code>. Note that no lexical checking
 281      *   is done on the absolute URI. In order to create a
 282      *   <code>LSParser</code> for any kind of schema types (i.e. the
 283      *   LSParser will be free to use any schema found), use the value
 284      *   <code>null</code>.
 285      * <p ><b>Note:</b>    For W3C XML Schema [<a href='http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/'>XML Schema Part 1</a>]
 286      *   , applications must use the value
 287      *   <code>"http://www.w3.org/2001/XMLSchema"</code>. For XML DTD [<a href='http://www.w3.org/TR/2000/REC-xml-20001006'>XML 1.0</a>],
 288      *   applications must use the value
 289      *   <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages
 290      *   are outside the scope of the W3C and therefore should recommend an
 291      *   absolute URI in order to use this method.
 292      * @return  The newly created <code>LSParser</code> object. This
 293      *   <code>LSParser</code> is either synchronous or asynchronous
 294      *   depending on the value of the <code>mode</code> argument.
 295      * <p ><b>Note:</b>    By default, the newly created <code>LSParser</code>
 296      *    does not contain a <code>DOMErrorHandler</code>, i.e. the value of
 297      *   the "<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030609/core.html#parameter-error-handler'>
 298      *   error-handler</a>" configuration parameter is <code>null</code>. However, implementations
 299      *   may provide a default error handler at creation time. In that case,
 300      *   the initial value of the <code>"error-handler"</code> configuration
 301      *   parameter on the new created <code>LSParser</code> contains a
 302      *   reference to the default error handler.
 303      * @exception DOMException
 304      *    NOT_SUPPORTED_ERR: Raised if the requested mode or schema type is
 305      *   not supported.
 306          */
 307         public LSParser createLSParser(short mode, String schemaType)
 308                 throws DOMException {
 309                 if (mode != DOMImplementationLS.MODE_SYNCHRONOUS || (schemaType !=null &&
 310                    !"http://www.w3.org/2001/XMLSchema".equals(schemaType) &&
 311                         !"http://www.w3.org/TR/REC-xml".equals(schemaType))) {
 312                         String msg =
 313                                 DOMMessageFormatter.formatMessage(
 314                                         DOMMessageFormatter.DOM_DOMAIN,
 315                                         "NOT_SUPPORTED_ERR",
 316                                         null);
 317                         throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 318                 }
 319                 if (schemaType != null
 320                         && schemaType.equals("http://www.w3.org/TR/REC-xml")) {
 321                         return new DOMParserImpl(new DTDConfiguration(),
 322                                 schemaType);
 323                 }
 324                 else {
 325                         // create default parser configuration validating against XMLSchemas
 326                         return new DOMParserImpl(new XIncludeAwareParserConfiguration(),
 327                                 schemaType);
 328                 }
 329         }
 330 
 331         /**
 332          * DOM Level 3 LS CR - Experimental.
 333          * Create a new <code>LSSerializer</code> object.
 334          * @return The newly created <code>LSSerializer</code> object.
 335          * <p ><b>Note:</b>    By default, the newly created
 336          * <code>LSSerializer</code> has no <code>DOMErrorHandler</code>,
 337          * i.e. the value of the <code>"error-handler"</code> configuration
 338          * parameter is <code>null</code>. However, implementations may
 339          * provide a default error handler at creation time. In that case, the
 340          * initial value of the <code>"error-handler"</code> configuration
 341          * parameter on the new created <code>LSSerializer</code> contains a
 342          * reference to the default error handler.
 343          */
 344         public LSSerializer createLSSerializer() {
 345             try {
 346                 Class serializerClass = ObjectFactory.findProviderClass(
 347                     "com.sun.org.apache.xml.internal.serializer.dom3.LSSerializerImpl",
 348                     ObjectFactory.findClassLoader(), true);
 349                 return (LSSerializer) serializerClass.newInstance();
 350             }
 351             catch (Exception e) {}
 352             // Fall back to Xerces' deprecated serializer if
 353             // the Xalan based serializer is unavailable.
 354             return new DOMSerializerImpl();
 355         }
 356 
 357         /**
 358          * DOM Level 3 LS CR - Experimental.
 359          * Create a new empty input source.
 360          * @return  The newly created input object.
 361          */
 362         public LSInput createLSInput() {
 363                 return new DOMInputImpl();
 364         }
 365 
 366         //
 367         // Protected methods
 368         //
 369         /** NON-DOM: retrieve validator. */
 370         synchronized RevalidationHandler getValidator(String schemaType) {
 371                 // REVISIT: implement retrieving DTD validator
 372         if (schemaType == XMLGrammarDescription.XML_SCHEMA) {
 373             // create new validator - we should not attempt
 374             // to restrict the number of validation handlers being
 375             // requested
 376             if(freeValidatorIndex < 0) {
 377                 return (RevalidationHandler) (ObjectFactory
 378                             .newInstance(
 379                                 "com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator",
 380                                 ObjectFactory.findClassLoader(),
 381                                 true));
 382             }
 383             // return first available validator
 384             RevalidationHandler val = validators[freeValidatorIndex];
 385             validators[freeValidatorIndex--] = null;
 386             return val;
 387         }
 388         else if(schemaType == XMLGrammarDescription.XML_DTD) {
 389             if(freeDTDValidatorIndex < 0) {
 390                 return (RevalidationHandler) (ObjectFactory
 391                             .newInstance(
 392                                 "com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator",
 393                                 ObjectFactory.findClassLoader(),
 394                                 true));
 395             }
 396             // return first available validator
 397             RevalidationHandler val = dtdValidators[freeDTDValidatorIndex];
 398             dtdValidators[freeDTDValidatorIndex--] = null;
 399             return val;
 400         }
 401         return null;
 402         }
 403 
 404         /** NON-DOM: release validator */
 405         synchronized void releaseValidator(String schemaType,
 406                                          RevalidationHandler validator) {
 407        // REVISIT: implement support for DTD validators as well
 408        if(schemaType == XMLGrammarDescription.XML_SCHEMA) {
 409            ++freeValidatorIndex;
 410            if (validators.length == freeValidatorIndex ){
 411                 // resize size of the validators
 412                 currentSize+=SIZE;
 413                 RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
 414                 System.arraycopy(validators, 0, newarray, 0, validators.length);
 415                 validators = newarray;
 416            }
 417            validators[freeValidatorIndex]=validator;
 418        }
 419        else if(schemaType == XMLGrammarDescription.XML_DTD) {
 420            ++freeDTDValidatorIndex;
 421            if (dtdValidators.length == freeDTDValidatorIndex ){
 422                 // resize size of the validators
 423                 currentSize+=SIZE;
 424                 RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
 425                 System.arraycopy(dtdValidators, 0, newarray, 0, dtdValidators.length);
 426                 dtdValidators = newarray;
 427            }
 428            dtdValidators[freeDTDValidatorIndex]=validator;
 429        }
 430         }
 431 
 432        /** NON-DOM:  increment document/doctype counter */
 433        protected synchronized int assignDocumentNumber() {
 434             return ++docAndDoctypeCounter;
 435        }
 436        /** NON-DOM:  increment document/doctype counter */
 437        protected synchronized int assignDocTypeNumber() {
 438             return ++docAndDoctypeCounter;
 439        }
 440 
 441     /* DOM Level 3 LS CR - Experimental.
 442      *
 443      * Create a new empty output destination object where
 444      * <code>LSOutput.characterStream</code>,
 445      * <code>LSOutput.byteStream</code>, <code>LSOutput.systemId</code>,
 446      * <code>LSOutput.encoding</code> are null.
 447 
 448      * @return  The newly created output object.
 449      */
 450        public LSOutput createLSOutput() {
 451            return new DOMOutputImpl();
 452        }
 453 
 454 } // class DOMImplementationImpl