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