KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > dtm > ref > IncrementalSAXSource_Xerces


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: IncrementalSAXSource_Xerces.java,v 1.15 2004/02/23 10:29:36 aruny Exp $
18  */

19
20 package org.apache.xml.dtm.ref;
21
22 import java.io.IOException JavaDoc;
23 import java.lang.reflect.Constructor JavaDoc;
24 import java.lang.reflect.Method JavaDoc;
25
26 import org.apache.xerces.parsers.SAXParser;
27 import org.apache.xml.res.XMLErrorResources;
28 import org.apache.xml.res.XMLMessages;
29
30 import org.xml.sax.InputSource JavaDoc;
31 import org.xml.sax.SAXException JavaDoc;
32 import org.xml.sax.XMLReader JavaDoc;
33
34
35 /** <p>IncrementalSAXSource_Xerces takes advantage of the fact that Xerces1
36  * incremental mode is already a coroutine of sorts, and just wraps our
37  * IncrementalSAXSource API around it.</p>
38  *
39  * <p>Usage example: See main().</p>
40  *
41  * <p>Status: Passes simple main() unit-test. NEEDS JAVADOC.</p>
42  * */

43 public class IncrementalSAXSource_Xerces
44   implements IncrementalSAXSource
45 {
46   //
47
// Reflection. To allow this to compile with both Xerces1 and Xerces2, which
48
// require very different methods and objects, we need to avoid static
49
// references to those APIs. So until Xerces2 is pervasive and we're willing
50
// to make it a prerequisite, we will rely upon relection.
51
//
52
Method JavaDoc fParseSomeSetup=null; // Xerces1 method
53
Method JavaDoc fParseSome=null; // Xerces1 method
54
Object JavaDoc fPullParserConfig=null; // Xerces2 pull control object
55
Method JavaDoc fConfigSetInput=null; // Xerces2 method
56
Method JavaDoc fConfigParse=null; // Xerces2 method
57
Method JavaDoc fSetInputSource=null; // Xerces2 pull control method
58
Constructor JavaDoc fConfigInputSourceCtor=null; // Xerces2 initialization method
59
Method JavaDoc fConfigSetByteStream=null; // Xerces2 initialization method
60
Method JavaDoc fConfigSetCharStream=null; // Xerces2 initialization method
61
Method JavaDoc fConfigSetEncoding=null; // Xerces2 initialization method
62
Method JavaDoc fReset=null; // Both Xerces1 and Xerces2, but diff. signatures
63

64   //
65
// Data
66
//
67
SAXParser fIncrementalParser;
68   private boolean fParseInProgress=false;
69
70   //
71
// Constructors
72
//
73

74   /** Create a IncrementalSAXSource_Xerces, and create a SAXParser
75    * to go with it. Xerces2 incremental parsing is only supported if
76    * this constructor is used, due to limitations in the Xerces2 API (as of
77    * Beta 3). If you don't like that restriction, tell the Xerces folks that
78    * there should be a simpler way to request incremental SAX parsing.
79    * */

80   public IncrementalSAXSource_Xerces()
81         throws NoSuchMethodException JavaDoc
82     {
83         try
84         {
85             // Xerces-2 incremental parsing support (as of Beta 3)
86
// ContentHandlers still get set on fIncrementalParser (to get
87
// conversion from XNI events to SAX events), but
88
// _control_ for incremental parsing must be exercised via the config.
89
//
90
// At this time there's no way to read the existing config, only
91
// to assert a new one... and only when creating a brand-new parser.
92
//
93
// Reflection is used to allow us to continue to compile against
94
// Xerces1. If/when we can abandon the older versions of the parser,
95
// this will simplify significantly.
96

97             // If we can't get the magic constructor, no need to look further.
98
Class JavaDoc xniConfigClass=ObjectFactory.findProviderClass(
99                             "org.apache.xerces.xni.parser.XMLParserConfiguration",
100                             ObjectFactory.findClassLoader(), true);
101             Class JavaDoc[] args1={xniConfigClass};
102             Constructor JavaDoc ctor=SAXParser.class.getConstructor(args1);
103             
104             // Build the parser configuration object. StandardParserConfiguration
105
// happens to implement XMLPullParserConfiguration, which is the API
106
// we're going to want to use.
107
Class JavaDoc xniStdConfigClass=ObjectFactory.findProviderClass(
108                             "org.apache.xerces.parsers.StandardParserConfiguration",
109                             ObjectFactory.findClassLoader(), true);
110             fPullParserConfig=xniStdConfigClass.newInstance();
111             Object JavaDoc[] args2={fPullParserConfig};
112             fIncrementalParser = (SAXParser)ctor.newInstance(args2);
113             
114             // Preload all the needed the configuration methods... I want to know they're
115
// all here before we commit to trying to use them, just in case the
116
// API changes again.
117
Class JavaDoc fXniInputSourceClass=ObjectFactory.findProviderClass(
118                             "org.apache.xerces.xni.parser.XMLInputSource",
119                             ObjectFactory.findClassLoader(), true);
120             Class JavaDoc[] args3={fXniInputSourceClass};
121             fConfigSetInput=xniStdConfigClass.getMethod("setInputSource",args3);
122
123             Class JavaDoc[] args4={String JavaDoc.class,String JavaDoc.class,String JavaDoc.class};
124             fConfigInputSourceCtor=fXniInputSourceClass.getConstructor(args4);
125             Class JavaDoc[] args5={java.io.InputStream JavaDoc.class};
126             fConfigSetByteStream=fXniInputSourceClass.getMethod("setByteStream",args5);
127             Class JavaDoc[] args6={java.io.Reader JavaDoc.class};
128             fConfigSetCharStream=fXniInputSourceClass.getMethod("setCharacterStream",args6);
129             Class JavaDoc[] args7={String JavaDoc.class};
130             fConfigSetEncoding=fXniInputSourceClass.getMethod("setEncoding",args7);
131
132             Class JavaDoc[] argsb={Boolean.TYPE};
133             fConfigParse=xniStdConfigClass.getMethod("parse",argsb);
134             Class JavaDoc[] noargs=new Class JavaDoc[0];
135             fReset=fIncrementalParser.getClass().getMethod("reset",noargs);
136         }
137         catch(Exception JavaDoc e)
138         {
139         // Fallback if this fails (implemented in createIncrementalSAXSource) is
140
// to attempt Xerces-1 incremental setup. Can't do tail-call in
141
// constructor, so create new, copy Xerces-1 initialization,
142
// then throw it away... Ugh.
143
IncrementalSAXSource_Xerces dummy=new IncrementalSAXSource_Xerces(new SAXParser());
144             this.fParseSomeSetup=dummy.fParseSomeSetup;
145             this.fParseSome=dummy.fParseSome;
146             this.fIncrementalParser=dummy.fIncrementalParser;
147         }
148   }
149
150   /** Create a IncrementalSAXSource_Xerces wrapped around
151    * an existing SAXParser. Currently this works only for recent
152    * releases of Xerces-1. Xerces-2 incremental is currently possible
153    * only if we are allowed to create the parser instance, due to
154    * limitations in the API exposed by Xerces-2 Beta 3; see the
155    * no-args constructor for that code.
156    *
157    * @exception if the SAXParser class doesn't support the Xerces
158    * incremental parse operations. In that case, caller should
159    * fall back upon the IncrementalSAXSource_Filter approach.
160    * */

161   public IncrementalSAXSource_Xerces(SAXParser parser)
162     throws NoSuchMethodException JavaDoc
163   {
164         // Reflection is used to allow us to compile against
165
// Xerces2. If/when we can abandon the older versions of the parser,
166
// this constructor will simply have to fail until/unless the
167
// Xerces2 incremental support is made available on previously
168
// constructed SAXParser instances.
169
fIncrementalParser=parser;
170         Class JavaDoc me=parser.getClass();
171     Class JavaDoc[] parms={InputSource JavaDoc.class};
172     fParseSomeSetup=me.getMethod("parseSomeSetup",parms);
173     parms=new Class JavaDoc[0];
174     fParseSome=me.getMethod("parseSome",parms);
175     // Fallback if this fails (implemented in createIncrementalSAXSource) is
176
// to use IncrementalSAXSource_Filter rather than Xerces-specific code.
177
}
178
179   //
180
// Factories
181
//
182
static public IncrementalSAXSource createIncrementalSAXSource()
183     {
184         try
185         {
186             return new IncrementalSAXSource_Xerces();
187         }
188         catch(NoSuchMethodException JavaDoc e)
189         {
190             // Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
191
// Fall back on filtering solution.
192
IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
193             iss.setXMLReader(new SAXParser());
194             return iss;
195         }
196   }
197     
198   static public IncrementalSAXSource
199   createIncrementalSAXSource(SAXParser parser) {
200         try
201         {
202             return new IncrementalSAXSource_Xerces(parser);
203         }
204         catch(NoSuchMethodException JavaDoc e)
205         {
206             // Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
207
// Fall back on filtering solution.
208
IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
209             iss.setXMLReader(parser);
210             return iss;
211         }
212   }
213
214   //
215
// Public methods
216
//
217

218   // Register handler directly with the incremental parser
219
public void setContentHandler(org.xml.sax.ContentHandler JavaDoc handler)
220   {
221     // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
222
// %OPT% Cast at asignment?
223
((XMLReader JavaDoc)fIncrementalParser).setContentHandler(handler);
224   }
225
226   // Register handler directly with the incremental parser
227
public void setLexicalHandler(org.xml.sax.ext.LexicalHandler JavaDoc handler)
228   {
229     // Not supported by all SAX2 parsers but should work in Xerces:
230
try
231     {
232       // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
233
// %OPT% Cast at asignment?
234
((XMLReader JavaDoc)fIncrementalParser).setProperty("http://xml.org/sax/properties/lexical-handler",
235                                      handler);
236     }
237     catch(org.xml.sax.SAXNotRecognizedException JavaDoc e)
238     {
239       // Nothing we can do about it
240
}
241     catch(org.xml.sax.SAXNotSupportedException JavaDoc e)
242     {
243       // Nothing we can do about it
244
}
245   }
246   
247   // Register handler directly with the incremental parser
248
public void setDTDHandler(org.xml.sax.DTDHandler JavaDoc handler)
249   {
250     // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
251
// %OPT% Cast at asignment?
252
((XMLReader JavaDoc)fIncrementalParser).setDTDHandler(handler);
253   }
254
255   //================================================================
256
/** startParse() is a simple API which tells the IncrementalSAXSource
257    * to begin reading a document.
258    *
259    * @throws SAXException is parse thread is already in progress
260    * or parsing can not be started.
261    * */

262   public void startParse(InputSource JavaDoc source) throws SAXException JavaDoc
263   {
264     if (fIncrementalParser==null)
265       throw new SAXException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_NEEDS_SAXPARSER, null)); //"startParse needs a non-null SAXParser.");
266
if (fParseInProgress)
267       throw new SAXException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_WHILE_PARSING, null)); //"startParse may not be called while parsing.");
268

269     boolean ok=false;
270
271     try
272     {
273       ok = parseSomeSetup(source);
274     }
275     catch(Exception JavaDoc ex)
276     {
277       throw new SAXException JavaDoc(ex);
278     }
279     
280     if(!ok)
281       throw new SAXException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_INIT_PARSER, null)); //"could not initialize parser with");
282
}
283
284   
285   /** deliverMoreNodes() is a simple API which tells the coroutine
286    * parser that we need more nodes. This is intended to be called
287    * from one of our partner routines, and serves to encapsulate the
288    * details of how incremental parsing has been achieved.
289    *
290    * @param parsemore If true, tells the incremental parser to generate
291    * another chunk of output. If false, tells the parser that we're
292    * satisfied and it can terminate parsing of this document.
293    * @return Boolean.TRUE if the CoroutineParser believes more data may be available
294    * for further parsing. Boolean.FALSE if parsing ran to completion.
295    * Exception if the parser objected for some reason.
296    * */

297   public Object JavaDoc deliverMoreNodes (boolean parsemore)
298   {
299     if(!parsemore)
300     {
301       fParseInProgress=false;
302       return Boolean.FALSE;
303     }
304
305     Object JavaDoc arg;
306     try {
307       boolean keepgoing = parseSome();
308       arg = keepgoing ? Boolean.TRUE : Boolean.FALSE;
309     } catch (SAXException JavaDoc ex) {
310       arg = ex;
311     } catch (IOException JavaDoc ex) {
312       arg = ex;
313     } catch (Exception JavaDoc ex) {
314       arg = new SAXException JavaDoc(ex);
315     }
316     return arg;
317   }
318     
319     // Private methods -- conveniences to hide the reflection details
320
private boolean parseSomeSetup(InputSource JavaDoc source)
321         throws SAXException JavaDoc, IOException JavaDoc, IllegalAccessException JavaDoc,
322                      java.lang.reflect.InvocationTargetException JavaDoc,
323                      java.lang.InstantiationException JavaDoc
324     {
325         if(fConfigSetInput!=null)
326         {
327             // Obtain input from SAX inputSource object, construct XNI version of
328
// that object. Logic adapted from Xerces2.
329
Object JavaDoc[] parms1={source.getPublicId(),source.getSystemId(),null};
330             Object JavaDoc xmlsource=fConfigInputSourceCtor.newInstance(parms1);
331             Object JavaDoc[] parmsa={source.getByteStream()};
332             fConfigSetByteStream.invoke(xmlsource,parmsa);
333             parmsa[0]=source.getCharacterStream();
334             fConfigSetCharStream.invoke(xmlsource,parmsa);
335             parmsa[0]=source.getEncoding();
336             fConfigSetEncoding.invoke(xmlsource,parmsa);
337
338             // Bugzilla5272 patch suggested by Sandy Gao.
339
// Has to be reflection to run with Xerces2
340
// after compilation against Xerces1. or vice
341
// versa, due to return type mismatches.
342
Object JavaDoc[] noparms=new Object JavaDoc[0];
343             fReset.invoke(fIncrementalParser,noparms);
344             
345             parmsa[0]=xmlsource;
346             fConfigSetInput.invoke(fPullParserConfig,parmsa);
347             
348             // %REVIEW% Do first pull. Should we instead just return true?
349
return parseSome();
350         }
351         else
352         {
353             Object JavaDoc[] parm={source};
354             Object JavaDoc ret=fParseSomeSetup.invoke(fIncrementalParser,parm);
355             return ((Boolean JavaDoc)ret).booleanValue();
356         }
357     }
358     
359     static final Object JavaDoc[] noparms=new Object JavaDoc[0]; // Would null work???
360
static final Object JavaDoc[] parmsfalse={Boolean.FALSE};
361     private boolean parseSome()
362         throws SAXException JavaDoc, IOException JavaDoc, IllegalAccessException JavaDoc,
363                      java.lang.reflect.InvocationTargetException JavaDoc
364     {
365         // Take next parsing step, return false iff parsing complete:
366
if(fConfigSetInput!=null)
367         {
368             Object JavaDoc ret=(Boolean JavaDoc)(fConfigParse.invoke(fPullParserConfig,parmsfalse));
369             return ((Boolean JavaDoc)ret).booleanValue();
370         }
371         else
372         {
373             Object JavaDoc ret=fParseSome.invoke(fIncrementalParser,noparms);
374             return ((Boolean JavaDoc)ret).booleanValue();
375         }
376     }
377     
378
379   //================================================================
380
/** Simple unit test. Attempt coroutine parsing of document indicated
381    * by first argument (as a URI), report progress.
382    */

383   public static void main(String JavaDoc args[])
384   {
385     System.out.println("Starting...");
386
387     CoroutineManager co = new CoroutineManager();
388     int appCoroutineID = co.co_joinCoroutineSet(-1);
389     if (appCoroutineID == -1)
390     {
391       System.out.println("ERROR: Couldn't allocate coroutine number.\n");
392       return;
393     }
394     IncrementalSAXSource parser=
395       createIncrementalSAXSource();
396
397     // Use a serializer as our sample output
398
org.apache.xml.serialize.XMLSerializer trace;
399     trace=new org.apache.xml.serialize.XMLSerializer(System.out,null);
400     parser.setContentHandler(trace);
401     parser.setLexicalHandler(trace);
402
403     // Tell coroutine to begin parsing, run while parsing is in progress
404

405     for(int arg=0;arg<args.length;++arg)
406     {
407       try
408       {
409         InputSource JavaDoc source = new InputSource JavaDoc(args[arg]);
410         Object JavaDoc result=null;
411         boolean more=true;
412         parser.startParse(source);
413         for(result = parser.deliverMoreNodes(more);
414             result==Boolean.TRUE;
415             result = parser.deliverMoreNodes(more))
416         {
417           System.out.println("\nSome parsing successful, trying more.\n");
418             
419           // Special test: Terminate parsing early.
420
if(arg+1<args.length && "!".equals(args[arg+1]))
421           {
422             ++arg;
423             more=false;
424           }
425             
426         }
427         
428         if (result instanceof Boolean JavaDoc && ((Boolean JavaDoc)result)==Boolean.FALSE)
429         {
430           System.out.println("\nParser ended (EOF or on request).\n");
431         }
432         else if (result == null) {
433           System.out.println("\nUNEXPECTED: Parser says shut down prematurely.\n");
434         }
435         else if (result instanceof Exception JavaDoc) {
436           throw new org.apache.xml.utils.WrappedRuntimeException((Exception JavaDoc)result);
437           // System.out.println("\nParser threw exception:");
438
// ((Exception)result).printStackTrace();
439
}
440         
441       }
442
443       catch(SAXException JavaDoc e)
444       {
445         e.printStackTrace();
446       }
447     }
448     
449   }
450
451   
452 } // class IncrementalSAXSource_Xerces
453
Popular Tags