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 if this implementation is compatible 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 (feature.equalsIgnoreCase("Core") 
 115                         && (anyVersion 
 116                             || version.equals("1.0") 
 117                             || version.equals("2.0") 
 118                             || version.equals("3.0"))) 
 119                     || (feature.equalsIgnoreCase("XML")
 120                         && (anyVersion
 121                             || version.equals("1.0")
 122                             || version.equals("2.0")
 123                             || version.equals("3.0")))
 124                     || (feature.equalsIgnoreCase("LS")
 125                         && (anyVersion 
 126                             || version.equals("3.0")))
 127                     || (feature.equalsIgnoreCase("ElementTraversal")
 128                         && (anyVersion 
 129                             || version.equals("1.0")));
 130         } // hasFeature(String,String):boolean
 131 
 132 
 133         /**
 134          * Introduced in DOM Level 2. <p>
 135          *
 136          * Creates an empty DocumentType node.
 137          *
 138          * @param qualifiedName The qualified name of the document type to be created.
 139          * @param publicID The document type public identifier.
 140          * @param systemID The document type system identifier.
 141          * @since WD-DOM-Level-2-19990923
 142          */
 143         public DocumentType createDocumentType( String qualifiedName,
 144                                     String publicID, String systemID) {
 145                 // REVISIT: this might allow creation of invalid name for DOCTYPE
 146                 //          xmlns prefix.
 147                 //          also there is no way for a user to turn off error checking.
 148                 checkQName(qualifiedName);
 149                 return new DocumentTypeImpl(null, qualifiedName, publicID, systemID);
 150         }
 151 
 152     final void checkQName(String qname){
 153         int index = qname.indexOf(':');
 154         int lastIndex = qname.lastIndexOf(':');
 155         int length = qname.length();
 156 
 157         // it is an error for NCName to have more than one ':'
 158         // check if it is valid QName [Namespace in XML production 6]
 159         if (index == 0 || index == length - 1 || lastIndex != index) {
 160             String msg =
 161                 DOMMessageFormatter.formatMessage(
 162                     DOMMessageFormatter.DOM_DOMAIN,
 163                     "NAMESPACE_ERR",
 164                     null);
 165             throw new DOMException(DOMException.NAMESPACE_ERR, msg);
 166         }
 167         int start = 0;
 168         // Namespace in XML production [6]
 169         if (index > 0) {
 170             // check that prefix is NCName
 171             if (!XMLChar.isNCNameStart(qname.charAt(start))) {
 172                 String msg =
 173                     DOMMessageFormatter.formatMessage(
 174                         DOMMessageFormatter.DOM_DOMAIN,
 175                         "INVALID_CHARACTER_ERR",
 176                         null);
 177                 throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 178             }
 179             for (int i = 1; i < index; i++) {
 180                 if (!XMLChar.isNCName(qname.charAt(i))) {
 181                     String msg =
 182                         DOMMessageFormatter.formatMessage(
 183                             DOMMessageFormatter.DOM_DOMAIN,
 184                             "INVALID_CHARACTER_ERR",
 185                             null);
 186                     throw new DOMException(
 187                         DOMException.INVALID_CHARACTER_ERR,
 188                         msg);
 189                 }
 190             }
 191             start = index + 1;
 192         }
 193 
 194         // check local part
 195         if (!XMLChar.isNCNameStart(qname.charAt(start))) {
 196             // REVISIT: add qname parameter to the message
 197             String msg =
 198                 DOMMessageFormatter.formatMessage(
 199                     DOMMessageFormatter.DOM_DOMAIN,
 200                     "INVALID_CHARACTER_ERR",
 201                     null);
 202             throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 203         }
 204         for (int i = start + 1; i < length; i++) {
 205             if (!XMLChar.isNCName(qname.charAt(i))) {
 206                 String msg =
 207                     DOMMessageFormatter.formatMessage(
 208                         DOMMessageFormatter.DOM_DOMAIN,
 209                         "INVALID_CHARACTER_ERR",
 210                         null);
 211                 throw new DOMException(DOMException.INVALID_CHARACTER_ERR, msg);
 212             }
 213         }
 214     }
 215 
 216 
 217         /**
 218          * Introduced in DOM Level 2. <p>
 219          *
 220          * Creates an XML Document object of the specified type with its document
 221          * element.
 222          *
 223          * @param namespaceURI     The namespace URI of the document
 224          *                         element to create, or null.
 225          * @param qualifiedName    The qualified name of the document
 226          *                         element to create.
 227          * @param doctype          The type of document to be created or null.<p>
 228          *
 229          *                         When doctype is not null, its
 230          *                         Node.ownerDocument attribute is set to
 231          *                         the document being created.
 232          * @return Document        A new Document object.
 233          * @throws DOMException    WRONG_DOCUMENT_ERR: Raised if doctype has
 234          *                         already been used with a different document.
 235          * @since WD-DOM-Level-2-19990923
 236          */
 237         public Document createDocument(
 238                 String namespaceURI,
 239                 String qualifiedName,
 240                 DocumentType doctype)
 241                 throws DOMException {
 242                 if (doctype != null && doctype.getOwnerDocument() != null) {
 243                         String msg =
 244                                 DOMMessageFormatter.formatMessage(
 245                                         DOMMessageFormatter.DOM_DOMAIN,
 246                                         "WRONG_DOCUMENT_ERR",
 247                                         null);
 248                         throw new DOMException(DOMException.WRONG_DOCUMENT_ERR, msg);
 249                 }
 250                 CoreDocumentImpl doc = new CoreDocumentImpl(doctype);
 251                 Element e = doc.createElementNS(namespaceURI, qualifiedName);
 252                 doc.appendChild(e);
 253                 return doc;
 254         }
 255 
 256         /**
 257          * DOM Level 3 WD - Experimental.
 258          */
 259         public Object getFeature(String feature, String version) {
 260             if (singleton.hasFeature(feature, version)) {
 261                 return singleton;
 262             }
 263             return null;
 264         }
 265 
 266         // DOM L3 LS
 267 
 268         /**
 269          * DOM Level 3 LS CR - Experimental.
 270      * Create a new <code>LSParser</code>. The newly constructed parser may
 271      * then be configured by means of its <code>DOMConfiguration</code>
 272      * object, and used to parse documents by means of its <code>parse</code>
 273      *  method.
 274      * @param mode  The <code>mode</code> argument is either
 275      *   <code>MODE_SYNCHRONOUS</code> or <code>MODE_ASYNCHRONOUS</code>, if
 276      *   <code>mode</code> is <code>MODE_SYNCHRONOUS</code> then the
 277      *   <code>LSParser</code> that is created will operate in synchronous
 278      *   mode, if it's <code>MODE_ASYNCHRONOUS</code> then the
 279      *   <code>LSParser</code> that is created will operate in asynchronous
 280      *   mode.
 281      * @param schemaType  An absolute URI representing the type of the schema
 282      *   language used during the load of a <code>Document</code> using the
 283      *   newly created <code>LSParser</code>. Note that no lexical checking
 284      *   is done on the absolute URI. In order to create a
 285      *   <code>LSParser</code> for any kind of schema types (i.e. the
 286      *   LSParser will be free to use any schema found), use the value
 287      *   <code>null</code>.
 288      * <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>]
 289      *   , applications must use the value
 290      *   <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>],
 291      *   applications must use the value
 292      *   <code>"http://www.w3.org/TR/REC-xml"</code>. Other Schema languages
 293      *   are outside the scope of the W3C and therefore should recommend an
 294      *   absolute URI in order to use this method.
 295      * @return  The newly created <code>LSParser</code> object. This
 296      *   <code>LSParser</code> is either synchronous or asynchronous
 297      *   depending on the value of the <code>mode</code> argument.
 298      * <p ><b>Note:</b>    By default, the newly created <code>LSParser</code>
 299      *    does not contain a <code>DOMErrorHandler</code>, i.e. the value of
 300      *   the "<a href='http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030609/core.html#parameter-error-handler'>
 301      *   error-handler</a>" configuration parameter is <code>null</code>. However, implementations
 302      *   may provide a default error handler at creation time. In that case,
 303      *   the initial value of the <code>"error-handler"</code> configuration
 304      *   parameter on the new created <code>LSParser</code> contains a
 305      *   reference to the default error handler.
 306      * @exception DOMException
 307      *    NOT_SUPPORTED_ERR: Raised if the requested mode or schema type is
 308      *   not supported.
 309          */
 310         public LSParser createLSParser(short mode, String schemaType)
 311                 throws DOMException {
 312                 if (mode != DOMImplementationLS.MODE_SYNCHRONOUS || (schemaType !=null &&
 313                    !"http://www.w3.org/2001/XMLSchema".equals(schemaType) &&
 314                         !"http://www.w3.org/TR/REC-xml".equals(schemaType))) {
 315                         String msg =
 316                                 DOMMessageFormatter.formatMessage(
 317                                         DOMMessageFormatter.DOM_DOMAIN,
 318                                         "NOT_SUPPORTED_ERR",
 319                                         null);
 320                         throw new DOMException(DOMException.NOT_SUPPORTED_ERR, msg);
 321                 }
 322                 if (schemaType != null
 323                         && schemaType.equals("http://www.w3.org/TR/REC-xml")) {
 324                         return new DOMParserImpl(new DTDConfiguration(),
 325                                 schemaType);
 326                 }
 327                 else {
 328                         // create default parser configuration validating against XMLSchemas
 329                         return new DOMParserImpl(new XIncludeAwareParserConfiguration(),
 330                                 schemaType);
 331                 }
 332         }
 333 
 334         /**
 335          * DOM Level 3 LS CR - Experimental.
 336          * Create a new <code>LSSerializer</code> object.
 337          * @return The newly created <code>LSSerializer</code> object.
 338          * <p ><b>Note:</b>    By default, the newly created
 339          * <code>LSSerializer</code> has no <code>DOMErrorHandler</code>,
 340          * i.e. the value of the <code>"error-handler"</code> configuration
 341          * parameter is <code>null</code>. However, implementations may
 342          * provide a default error handler at creation time. In that case, the
 343          * initial value of the <code>"error-handler"</code> configuration
 344          * parameter on the new created <code>LSSerializer</code> contains a
 345          * reference to the default error handler.
 346          */
 347         public LSSerializer createLSSerializer() {
 348             try {
 349                 return new com.sun.org.apache.xml.internal.serializer.dom3.LSSerializerImpl();
 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 new com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaValidator();
 378             }
 379             // return first available validator
 380             RevalidationHandler val = validators[freeValidatorIndex];
 381             validators[freeValidatorIndex--] = null;
 382             return val;
 383         }
 384         else if(schemaType == XMLGrammarDescription.XML_DTD) {
 385             if(freeDTDValidatorIndex < 0) {
 386                 return new com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator();
 387             }
 388             // return first available validator
 389             RevalidationHandler val = dtdValidators[freeDTDValidatorIndex];
 390             dtdValidators[freeDTDValidatorIndex--] = null;
 391             return val;
 392         }
 393         return null;
 394         }
 395 
 396         /** NON-DOM: release validator */
 397         synchronized void releaseValidator(String schemaType,
 398                                          RevalidationHandler validator) {
 399        // REVISIT: implement support for DTD validators as well
 400        if(schemaType == XMLGrammarDescription.XML_SCHEMA) {
 401            ++freeValidatorIndex;
 402            if (validators.length == freeValidatorIndex ){
 403                 // resize size of the validators
 404                 currentSize+=SIZE;
 405                 RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
 406                 System.arraycopy(validators, 0, newarray, 0, validators.length);
 407                 validators = newarray;
 408            }
 409            validators[freeValidatorIndex]=validator;
 410        }
 411        else if(schemaType == XMLGrammarDescription.XML_DTD) {
 412            ++freeDTDValidatorIndex;
 413            if (dtdValidators.length == freeDTDValidatorIndex ){
 414                 // resize size of the validators
 415                 currentSize+=SIZE;
 416                 RevalidationHandler newarray[] =  new RevalidationHandler[currentSize];
 417                 System.arraycopy(dtdValidators, 0, newarray, 0, dtdValidators.length);
 418                 dtdValidators = newarray;
 419            }
 420            dtdValidators[freeDTDValidatorIndex]=validator;
 421        }
 422         }
 423 
 424        /** NON-DOM:  increment document/doctype counter */
 425        protected synchronized int assignDocumentNumber() {
 426             return ++docAndDoctypeCounter;
 427        }
 428        /** NON-DOM:  increment document/doctype counter */
 429        protected synchronized int assignDocTypeNumber() {
 430             return ++docAndDoctypeCounter;
 431        }
 432 
 433     /* DOM Level 3 LS CR - Experimental.
 434      *
 435      * Create a new empty output destination object where
 436      * <code>LSOutput.characterStream</code>,
 437      * <code>LSOutput.byteStream</code>, <code>LSOutput.systemId</code>,
 438      * <code>LSOutput.encoding</code> are null.
 439 
 440      * @return  The newly created output object.
 441      */
 442        public LSOutput createLSOutput() {
 443            return new DOMOutputImpl();
 444        }
 445 
 446 } // class DOMImplementationImpl