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.xalan.internal.xsltc.dom;
23 
24 import javax.xml.stream.XMLEventReader;
25 import javax.xml.stream.XMLStreamReader;
26 import javax.xml.transform.Source;
27 import javax.xml.transform.dom.DOMSource;
28 import javax.xml.transform.sax.SAXSource;
29 import javax.xml.transform.stream.StreamSource;
30 import javax.xml.transform.stax.StAXSource;
31 
32 import com.sun.org.apache.xml.internal.dtm.DTM;
33 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase;
34 import com.sun.org.apache.xml.internal.dtm.DTMException;
35 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter;
36 import com.sun.org.apache.xml.internal.dtm.ref.DTMManagerDefault;
37 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
38 import com.sun.org.apache.xml.internal.res.XMLMessages;
39 import com.sun.org.apache.xml.internal.utils.SystemIDResolver;
40 import com.sun.org.apache.xalan.internal.xsltc.trax.DOM2SAX;
41 import com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX;
42 import com.sun.org.apache.xalan.internal.xsltc.trax.StAXStream2SAX;
43 
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXNotRecognizedException;
46 import org.xml.sax.SAXNotSupportedException;
47 import org.xml.sax.XMLReader;
48 
49 /**
50  * The default implementation for the DTMManager.
51  */
52 public class XSLTCDTMManager extends DTMManagerDefault
53 {
54 
55     /** Set this to true if you want a dump of the DTM after creation */
56     private static final boolean DUMPTREE = false;
57 
58     /** Set this to true if you want basic diagnostics */
59     private static final boolean DEBUG = false;
60 
61     /**
62      * Constructor DTMManagerDefault
63      *
64      */
XSLTCDTMManager()65     public XSLTCDTMManager()
66     {
67         super();
68     }
69 
70     /**
71      * Obtain a new instance of a <code>DTMManager</code>.
72      * This static method creates a new factory instance.
73      * The current implementation just returns a new XSLTCDTMManager instance.
74      */
newInstance()75     public static XSLTCDTMManager newInstance()
76     {
77         return new XSLTCDTMManager();
78     }
79 
80     /**
81      * Creates a new instance of the XSLTC DTM Manager service.
82      * Creates a new instance of the default class
83      * <code>com.sun.org.apache.xalan.internal.xsltc.dom.XSLTCDTMManager</code>.
84      */
createNewDTMManagerInstance()85       public static XSLTCDTMManager createNewDTMManagerInstance() {
86          return newInstance();
87       }
88 
89     /**
90      * Get an instance of a DTM, loaded with the content from the
91      * specified source.  If the unique flag is true, a new instance will
92      * always be returned.  Otherwise it is up to the DTMManager to return a
93      * new instance or an instance that it already created and may be being used
94      * by someone else.
95      * (I think more parameters will need to be added for error handling, and
96      * entity resolution).
97      *
98      * @param source the specification of the source object.
99      * @param unique true if the returned DTM must be unique, probably because it
100      * is going to be mutated.
101      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
102      *                         be null.
103      * @param incremental true if the DTM should be built incrementally, if
104      *                    possible.
105      * @param doIndexing true if the caller considers it worth it to use
106      *                   indexing schemes.
107      *
108      * @return a non-null DTM reference.
109      */
110     @Override
getDTM(Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing)111     public DTM getDTM(Source source, boolean unique,
112                       DTMWSFilter whiteSpaceFilter, boolean incremental,
113                       boolean doIndexing)
114     {
115         return getDTM(source, unique, whiteSpaceFilter, incremental,
116                       doIndexing, false, 0, true, false);
117     }
118 
119     /**
120      * Get an instance of a DTM, loaded with the content from the
121      * specified source.  If the unique flag is true, a new instance will
122      * always be returned.  Otherwise it is up to the DTMManager to return a
123      * new instance or an instance that it already created and may be being used
124      * by someone else.
125      * (I think more parameters will need to be added for error handling, and
126      * entity resolution).
127      *
128      * @param source the specification of the source object.
129      * @param unique true if the returned DTM must be unique, probably because it
130      * is going to be mutated.
131      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
132      *                         be null.
133      * @param incremental true if the DTM should be built incrementally, if
134      *                    possible.
135      * @param doIndexing true if the caller considers it worth it to use
136      *                   indexing schemes.
137      * @param buildIdIndex true if the id index table should be built.
138      *
139      * @return a non-null DTM reference.
140      */
getDTM(Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing, boolean buildIdIndex)141     public DTM getDTM(Source source, boolean unique,
142                       DTMWSFilter whiteSpaceFilter, boolean incremental,
143                       boolean doIndexing, boolean buildIdIndex)
144     {
145         return getDTM(source, unique, whiteSpaceFilter, incremental,
146                       doIndexing, false, 0, buildIdIndex, false);
147     }
148 
149     /**
150      * Get an instance of a DTM, loaded with the content from the
151      * specified source.  If the unique flag is true, a new instance will
152      * always be returned.  Otherwise it is up to the DTMManager to return a
153      * new instance or an instance that it already created and may be being used
154      * by someone else.
155      * (I think more parameters will need to be added for error handling, and
156      * entity resolution).
157      *
158      * @param source the specification of the source object.
159      * @param unique true if the returned DTM must be unique, probably because it
160      * is going to be mutated.
161      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
162      *                         be null.
163      * @param incremental true if the DTM should be built incrementally, if
164      *                    possible.
165      * @param doIndexing true if the caller considers it worth it to use
166      *                   indexing schemes.
167      * @param buildIdIndex true if the id index table should be built.
168      * @param newNameTable true if we want to use a separate ExpandedNameTable
169      *                     for this DTM.
170      *
171      * @return a non-null DTM reference.
172      */
getDTM(Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing, boolean buildIdIndex, boolean newNameTable)173   public DTM getDTM(Source source, boolean unique,
174                     DTMWSFilter whiteSpaceFilter, boolean incremental,
175                     boolean doIndexing, boolean buildIdIndex,
176                     boolean newNameTable)
177   {
178     return getDTM(source, unique, whiteSpaceFilter, incremental,
179                   doIndexing, false, 0, buildIdIndex, newNameTable);
180   }
181 
182   /**
183      * Get an instance of a DTM, loaded with the content from the
184      * specified source.  If the unique flag is true, a new instance will
185      * always be returned.  Otherwise it is up to the DTMManager to return a
186      * new instance or an instance that it already created and may be being used
187      * by someone else.
188      * (I think more parameters will need to be added for error handling, and
189      * entity resolution).
190      *
191      * @param source the specification of the source object.
192      * @param unique true if the returned DTM must be unique, probably because it
193      * is going to be mutated.
194      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
195      *                         be null.
196      * @param incremental true if the DTM should be built incrementally, if
197      *                    possible.
198      * @param doIndexing true if the caller considers it worth it to use
199      *                   indexing schemes.
200      * @param hasUserReader true if <code>source</code> is a
201      *                      <code>SAXSource</code> object that has an
202      *                      <code>XMLReader</code>, that was specified by the
203      *                      user.
204      * @param size  Specifies initial size of tables that represent the DTM
205      * @param buildIdIndex true if the id index table should be built.
206      *
207      * @return a non-null DTM reference.
208      */
getDTM(Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing, boolean hasUserReader, int size, boolean buildIdIndex)209     public DTM getDTM(Source source, boolean unique,
210                       DTMWSFilter whiteSpaceFilter, boolean incremental,
211                       boolean doIndexing, boolean hasUserReader, int size,
212                       boolean buildIdIndex)
213     {
214       return getDTM(source, unique, whiteSpaceFilter, incremental,
215                     doIndexing, hasUserReader, size,
216                     buildIdIndex, false);
217   }
218 
219   /**
220      * Get an instance of a DTM, loaded with the content from the
221      * specified source.  If the unique flag is true, a new instance will
222      * always be returned.  Otherwise it is up to the DTMManager to return a
223      * new instance or an instance that it already created and may be being used
224      * by someone else.
225      * (I think more parameters will need to be added for error handling, and
226      * entity resolution).
227      *
228      * @param source the specification of the source object.
229      * @param unique true if the returned DTM must be unique, probably because it
230      * is going to be mutated.
231      * @param whiteSpaceFilter Enables filtering of whitespace nodes, and may
232      *                         be null.
233      * @param incremental true if the DTM should be built incrementally, if
234      *                    possible.
235      * @param doIndexing true if the caller considers it worth it to use
236      *                   indexing schemes.
237      * @param hasUserReader true if <code>source</code> is a
238      *                      <code>SAXSource</code> object that has an
239      *                      <code>XMLReader</code>, that was specified by the
240      *                      user.
241      * @param size  Specifies initial size of tables that represent the DTM
242      * @param buildIdIndex true if the id index table should be built.
243      * @param newNameTable true if we want to use a separate ExpandedNameTable
244      *                     for this DTM.
245      *
246      * @return a non-null DTM reference.
247      */
getDTM(Source source, boolean unique, DTMWSFilter whiteSpaceFilter, boolean incremental, boolean doIndexing, boolean hasUserReader, int size, boolean buildIdIndex, boolean newNameTable)248   public DTM getDTM(Source source, boolean unique,
249                     DTMWSFilter whiteSpaceFilter, boolean incremental,
250                     boolean doIndexing, boolean hasUserReader, int size,
251                     boolean buildIdIndex, boolean newNameTable)
252   {
253         if(DEBUG && null != source) {
254             System.out.println("Starting "+
255                          (unique ? "UNIQUE" : "shared")+
256                          " source: "+source.getSystemId());
257         }
258 
259         int dtmPos = getFirstFreeDTMID();
260         int documentID = dtmPos << IDENT_DTM_NODE_BITS;
261 
262         if ((null != source) && source instanceof StAXSource) {
263             final StAXSource staxSource = (StAXSource)source;
264             StAXEvent2SAX staxevent2sax = null;
265             StAXStream2SAX staxStream2SAX = null;
266             if (staxSource.getXMLEventReader() != null) {
267                 final XMLEventReader xmlEventReader = staxSource.getXMLEventReader();
268                 staxevent2sax = new StAXEvent2SAX(xmlEventReader);
269             } else if (staxSource.getXMLStreamReader() != null) {
270                 final XMLStreamReader xmlStreamReader = staxSource.getXMLStreamReader();
271                 staxStream2SAX = new StAXStream2SAX(xmlStreamReader);
272             }
273 
274             SAXImpl dtm;
275 
276             if (size <= 0) {
277                 dtm = new SAXImpl(this, source, documentID,
278                                   whiteSpaceFilter, null, doIndexing,
279                                   DTMDefaultBase.DEFAULT_BLOCKSIZE,
280                                   buildIdIndex, newNameTable);
281             } else {
282                 dtm = new SAXImpl(this, source, documentID,
283                                   whiteSpaceFilter, null, doIndexing,
284                                   size, buildIdIndex, newNameTable);
285             }
286 
287             dtm.setDocumentURI(source.getSystemId());
288 
289             addDTM(dtm, dtmPos, 0);
290 
291             try {
292                 if (staxevent2sax != null) {
293                     staxevent2sax.setContentHandler(dtm);
294                     staxevent2sax.parse();
295                 }
296                 else if (staxStream2SAX != null) {
297                     staxStream2SAX.setContentHandler(dtm);
298                     staxStream2SAX.parse();
299                 }
300 
301             }
302             catch (RuntimeException re) {
303                 throw re;
304             }
305             catch (Exception e) {
306                 throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
307             }
308 
309             return dtm;
310         }else if ((null != source) && source instanceof DOMSource) {
311             final DOMSource domsrc = (DOMSource) source;
312             final org.w3c.dom.Node node = domsrc.getNode();
313             final DOM2SAX dom2sax = new DOM2SAX(node);
314 
315             SAXImpl dtm;
316 
317             if (size <= 0) {
318                 dtm = new SAXImpl(this, source, documentID,
319                                   whiteSpaceFilter, null, doIndexing,
320                                   DTMDefaultBase.DEFAULT_BLOCKSIZE,
321                                   buildIdIndex, newNameTable);
322             } else {
323                 dtm = new SAXImpl(this, source, documentID,
324                                   whiteSpaceFilter, null, doIndexing,
325                                   size, buildIdIndex, newNameTable);
326             }
327 
328             dtm.setDocumentURI(source.getSystemId());
329 
330             addDTM(dtm, dtmPos, 0);
331 
332             dom2sax.setContentHandler(dtm);
333 
334             try {
335                 dom2sax.parse();
336             }
337             catch (RuntimeException re) {
338                 throw re;
339             }
340             catch (Exception e) {
341                 throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
342             }
343 
344             return dtm;
345         }
346         else
347         {
348             boolean isSAXSource = (null != source)
349                                   ? (source instanceof SAXSource) : true;
350             boolean isStreamSource = (null != source)
351                                   ? (source instanceof StreamSource) : false;
352 
353             if (isSAXSource || isStreamSource) {
354                 XMLReader reader;
355                 InputSource xmlSource;
356 
357                 if (null == source) {
358                     xmlSource = null;
359                     reader = null;
360                     hasUserReader = false;  // Make sure the user didn't lie
361                 }
362                 else {
363                     reader = getXMLReader(source);
364                     xmlSource = SAXSource.sourceToInputSource(source);
365 
366                     String urlOfSource = xmlSource.getSystemId();
367 
368                     if (null != urlOfSource) {
369                         try {
370                             urlOfSource = SystemIDResolver.getAbsoluteURI(urlOfSource);
371                         }
372                         catch (Exception e) {
373                             // %REVIEW% Is there a better way to send a warning?
374                             System.err.println("Can not absolutize URL: " + urlOfSource);
375                         }
376 
377                         xmlSource.setSystemId(urlOfSource);
378                     }
379                 }
380 
381                 // Create the basic SAX2DTM.
382                 SAXImpl dtm;
383                 if (size <= 0) {
384                     dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
385                                       null, doIndexing,
386                                       DTMDefaultBase.DEFAULT_BLOCKSIZE,
387                                       buildIdIndex, newNameTable);
388                 } else {
389                     dtm = new SAXImpl(this, source, documentID, whiteSpaceFilter,
390                             null, doIndexing, size, buildIdIndex, newNameTable);
391                 }
392 
393                 // Go ahead and add the DTM to the lookup table.  This needs to be
394                 // done before any parsing occurs. Note offset 0, since we've just
395                 // created a new DTM.
396                 addDTM(dtm, dtmPos, 0);
397 
398                 if (null == reader) {
399                     // Then the user will construct it themselves.
400                     return dtm;
401                 }
402 
403                 reader.setContentHandler(dtm.getBuilder());
404 
405                 if (!hasUserReader || null == reader.getDTDHandler()) {
406                     reader.setDTDHandler(dtm);
407                 }
408 
409                 if(!hasUserReader || null == reader.getErrorHandler()) {
410                     reader.setErrorHandler(dtm);
411                 }
412 
413                 try {
414                     reader.setProperty("http://xml.org/sax/properties/lexical-handler", dtm);
415                 }
416                 catch (SAXNotRecognizedException e){}
417                 catch (SAXNotSupportedException e){}
418 
419                 try {
420                     reader.parse(xmlSource);
421                 }
422                 catch (RuntimeException re) {
423                     throw re;
424                 }
425                 catch (Exception e) {
426                     throw new com.sun.org.apache.xml.internal.utils.WrappedRuntimeException(e);
427                 } finally {
428                     if (!hasUserReader) {
429                         releaseXMLReader(reader);
430                     }
431                 }
432 
433                 if (DUMPTREE) {
434                     System.out.println("Dumping SAX2DOM");
435                     dtm.dumpDTM(System.err);
436                 }
437 
438                 return dtm;
439             }
440             else {
441                 // It should have been handled by a derived class or the caller
442                 // made a mistake.
443                 throw new DTMException(XMLMessages.createXMLMessage(XMLErrorResources.ER_NOT_SUPPORTED, new Object[]{source}));
444             }
445         }
446     }
447 }
448