KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > dtm > ref > IncrementalSAXSource_Filter


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_Filter.java,v 1.11 2004/02/16 23:06:11 minchau Exp $
18  */

19
20 package com.sun.org.apache.xml.internal.dtm.ref;
21
22 import java.io.IOException JavaDoc;
23
24 import com.sun.org.apache.xml.internal.res.XMLErrorResources;
25 import com.sun.org.apache.xml.internal.res.XMLMessages;
26 import com.sun.org.apache.xml.internal.utils.ThreadControllerWrapper;
27
28 import org.xml.sax.Attributes JavaDoc;
29 import org.xml.sax.ContentHandler JavaDoc;
30 import org.xml.sax.DTDHandler JavaDoc;
31 import org.xml.sax.ErrorHandler JavaDoc;
32 import org.xml.sax.InputSource JavaDoc;
33 import org.xml.sax.Locator JavaDoc;
34 import org.xml.sax.SAXException JavaDoc;
35 import org.xml.sax.SAXNotRecognizedException JavaDoc;
36 import org.xml.sax.SAXNotSupportedException JavaDoc;
37 import org.xml.sax.SAXParseException JavaDoc;
38 import org.xml.sax.XMLReader JavaDoc;
39 import org.xml.sax.ext.LexicalHandler JavaDoc;
40
41 /** <p>IncrementalSAXSource_Filter implements IncrementalSAXSource, using a
42  * standard SAX2 event source as its input and parcelling out those
43  * events gradually in reponse to deliverMoreNodes() requests. Output from the
44  * filter will be passed along to a SAX handler registered as our
45  * listener, but those callbacks will pass through a counting stage
46  * which periodically yields control back to the controller coroutine.
47  * </p>
48  *
49  * <p>%REVIEW%: This filter is not currenly intended to be reusable
50  * for parsing additional streams/documents. We may want to consider
51  * making it resettable at some point in the future. But it's a
52  * small object, so that'd be mostly a convenience issue; the cost
53  * of allocating each time is trivial compared to the cost of processing
54  * any nontrival stream.</p>
55  *
56  * <p>For a brief usage example, see the unit-test _main() method.</p>
57  *
58  * <p>This is a simplification of the old CoroutineSAXParser, focusing
59  * specifically on filtering. The resulting controller protocol is _far_
60  * simpler and less error-prone; the only controller operation is deliverMoreNodes(),
61  * and the only requirement is that deliverMoreNodes(false) be called if you want to
62  * discard the rest of the stream and the previous deliverMoreNodes() didn't return
63  * false.
64  *
65  * This class is final and package private for security reasons. Please
66  * see CR 6537912 for further details.
67  *
68  * */

69 final class IncrementalSAXSource_Filter
70 implements IncrementalSAXSource, ContentHandler JavaDoc, DTDHandler JavaDoc, LexicalHandler JavaDoc, ErrorHandler JavaDoc, Runnable JavaDoc
71 {
72   boolean DEBUG=false; //Internal status report
73

74   //
75
// Data
76
//
77
private CoroutineManager fCoroutineManager = null;
78   private int fControllerCoroutineID = -1;
79   private int fSourceCoroutineID = -1;
80
81   private ContentHandler JavaDoc clientContentHandler=null; // %REVIEW% support multiple?
82
private LexicalHandler JavaDoc clientLexicalHandler=null; // %REVIEW% support multiple?
83
private DTDHandler JavaDoc clientDTDHandler=null; // %REVIEW% support multiple?
84
private ErrorHandler JavaDoc clientErrorHandler=null; // %REVIEW% support multiple?
85
private int eventcounter;
86   private int frequency=5;
87
88   // Flag indicating that no more events should be delivered -- either
89
// because input stream ran to completion (endDocument), or because
90
// the user requested an early stop via deliverMoreNodes(false).
91
private boolean fNoMoreEvents=false;
92
93   // Support for startParse()
94
private XMLReader JavaDoc fXMLReader=null;
95   private InputSource JavaDoc fXMLReaderInputSource=null;
96
97   //
98
// Constructors
99
//
100

101   public IncrementalSAXSource_Filter() {
102     this.init( new CoroutineManager(), -1, -1);
103   }
104   
105   /** Create a IncrementalSAXSource_Filter which is not yet bound to a specific
106    * SAX event source.
107    * */

108   public IncrementalSAXSource_Filter(CoroutineManager co, int controllerCoroutineID)
109   {
110     this.init( co, controllerCoroutineID, -1 );
111   }
112
113   //
114
// Factories
115
//
116
static public IncrementalSAXSource createIncrementalSAXSource(CoroutineManager co, int controllerCoroutineID) {
117     return new IncrementalSAXSource_Filter(co, controllerCoroutineID);
118   }
119
120   //
121
// Public methods
122
//
123

124   public void init( CoroutineManager co, int controllerCoroutineID,
125                     int sourceCoroutineID)
126   {
127     if(co==null)
128       co = new CoroutineManager();
129     fCoroutineManager = co;
130     fControllerCoroutineID = co.co_joinCoroutineSet(controllerCoroutineID);
131     fSourceCoroutineID = co.co_joinCoroutineSet(sourceCoroutineID);
132     if (fControllerCoroutineID == -1 || fSourceCoroutineID == -1)
133       throw new RuntimeException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_COJOINROUTINESET_FAILED, null)); //"co_joinCoroutineSet() failed");
134

135     fNoMoreEvents=false;
136     eventcounter=frequency;
137   }
138     
139   /** Bind our input streams to an XMLReader.
140    *
141    * Just a convenience routine; obviously you can explicitly register
142    * this as a listener with the same effect.
143    * */

144   public void setXMLReader(XMLReader JavaDoc eventsource)
145   {
146     fXMLReader=eventsource;
147     eventsource.setContentHandler(this);
148     eventsource.setDTDHandler(this);
149     eventsource.setErrorHandler(this); // to report fatal errors in filtering mode
150

151     // Not supported by all SAX2 filters:
152
try
153     {
154       eventsource.
155         setProperty("http://xml.org/sax/properties/lexical-handler",
156                     this);
157     }
158     catch(SAXNotRecognizedException JavaDoc e)
159     {
160       // Nothing we can do about it
161
}
162     catch(SAXNotSupportedException JavaDoc e)
163     {
164       // Nothing we can do about it
165
}
166
167     // Should we also bind as other varieties of handler?
168
// (DTDHandler and so on)
169
}
170
171   // Register a content handler for us to output to
172
public void setContentHandler(ContentHandler JavaDoc handler)
173   {
174     clientContentHandler=handler;
175   }
176   // Register a DTD handler for us to output to
177
public void setDTDHandler(DTDHandler JavaDoc handler)
178   {
179     clientDTDHandler=handler;
180   }
181   // Register a lexical handler for us to output to
182
// Not all filters support this...
183
// ??? Should we register directly on the filter?
184
// NOTE NAME -- subclassing issue in the Xerces version
185
public void setLexicalHandler(LexicalHandler JavaDoc handler)
186   {
187     clientLexicalHandler=handler;
188   }
189   // Register an error handler for us to output to
190
// NOTE NAME -- subclassing issue in the Xerces version
191
public void setErrHandler(ErrorHandler JavaDoc handler)
192   {
193     clientErrorHandler=handler;
194   }
195
196   // Set the number of events between resumes of our coroutine
197
// Immediately resets number of events before _next_ resume as well.
198
public void setReturnFrequency(int events)
199   {
200     if(events<1) events=1;
201     frequency=eventcounter=events;
202   }
203   
204   //
205
// ContentHandler methods
206
// These pass the data to our client ContentHandler...
207
// but they also count the number of events passing through,
208
// and resume our coroutine each time that counter hits zero and
209
// is reset.
210
//
211
// Note that for everything except endDocument and fatalError, we do the count-and-yield
212
// BEFORE passing the call along. I'm hoping that this will encourage JIT
213
// compilers to realize that these are tail-calls, reducing the expense of
214
// the additional layer of data flow.
215
//
216
// %REVIEW% Glenn suggests that pausing after endElement, endDocument,
217
// and characters may be sufficient. I actually may not want to
218
// stop after characters, since in our application these wind up being
219
// concatenated before they're processed... but that risks huge blocks of
220
// text causing greater than usual readahead. (Unlikely? Consider the
221
// possibility of a large base-64 block in a SOAP stream.)
222
//
223
public void characters(char[] ch, int start, int length)
224        throws org.xml.sax.SAXException JavaDoc
225   {
226     if(--eventcounter<=0)
227       {
228         co_yield(true);
229         eventcounter=frequency;
230       }
231     if(clientContentHandler!=null)
232       clientContentHandler.characters(ch,start,length);
233   }
234   public void endDocument()
235        throws org.xml.sax.SAXException JavaDoc
236   {
237     // EXCEPTION: In this case we need to run the event BEFORE we yield.
238
if(clientContentHandler!=null)
239       clientContentHandler.endDocument();
240
241     eventcounter=0;
242     co_yield(false);
243   }
244   public void endElement(java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName,
245       java.lang.String JavaDoc qName)
246        throws org.xml.sax.SAXException JavaDoc
247   {
248     if(--eventcounter<=0)
249       {
250         co_yield(true);
251         eventcounter=frequency;
252       }
253     if(clientContentHandler!=null)
254       clientContentHandler.endElement(namespaceURI,localName,qName);
255   }
256   public void endPrefixMapping(java.lang.String JavaDoc prefix)
257        throws org.xml.sax.SAXException JavaDoc
258   {
259     if(--eventcounter<=0)
260       {
261         co_yield(true);
262         eventcounter=frequency;
263       }
264     if(clientContentHandler!=null)
265       clientContentHandler.endPrefixMapping(prefix);
266   }
267   public void ignorableWhitespace(char[] ch, int start, int length)
268        throws org.xml.sax.SAXException JavaDoc
269   {
270     if(--eventcounter<=0)
271       {
272         co_yield(true);
273         eventcounter=frequency;
274       }
275     if(clientContentHandler!=null)
276       clientContentHandler.ignorableWhitespace(ch,start,length);
277   }
278   public void processingInstruction(java.lang.String JavaDoc target, java.lang.String JavaDoc data)
279        throws org.xml.sax.SAXException JavaDoc
280   {
281     if(--eventcounter<=0)
282       {
283         co_yield(true);
284         eventcounter=frequency;
285       }
286     if(clientContentHandler!=null)
287       clientContentHandler.processingInstruction(target,data);
288   }
289   public void setDocumentLocator(Locator JavaDoc locator)
290   {
291     if(--eventcounter<=0)
292       {
293         // This can cause a hang. -sb
294
// co_yield(true);
295
eventcounter=frequency;
296       }
297     if(clientContentHandler!=null)
298       clientContentHandler.setDocumentLocator(locator);
299   }
300   public void skippedEntity(java.lang.String JavaDoc name)
301        throws org.xml.sax.SAXException JavaDoc
302   {
303     if(--eventcounter<=0)
304       {
305         co_yield(true);
306         eventcounter=frequency;
307       }
308     if(clientContentHandler!=null)
309       clientContentHandler.skippedEntity(name);
310   }
311   public void startDocument()
312        throws org.xml.sax.SAXException JavaDoc
313   {
314     co_entry_pause();
315
316     // Otherwise, begin normal event delivery
317
if(--eventcounter<=0)
318       {
319         co_yield(true);
320         eventcounter=frequency;
321       }
322     if(clientContentHandler!=null)
323       clientContentHandler.startDocument();
324   }
325   public void startElement(java.lang.String JavaDoc namespaceURI, java.lang.String JavaDoc localName,
326       java.lang.String JavaDoc qName, Attributes JavaDoc atts)
327        throws org.xml.sax.SAXException JavaDoc
328   {
329     if(--eventcounter<=0)
330       {
331         co_yield(true);
332         eventcounter=frequency;
333       }
334     if(clientContentHandler!=null)
335       clientContentHandler.startElement(namespaceURI, localName, qName, atts);
336   }
337   public void startPrefixMapping(java.lang.String JavaDoc prefix, java.lang.String JavaDoc uri)
338        throws org.xml.sax.SAXException JavaDoc
339   {
340     if(--eventcounter<=0)
341       {
342         co_yield(true);
343         eventcounter=frequency;
344       }
345     if(clientContentHandler!=null)
346       clientContentHandler.startPrefixMapping(prefix,uri);
347   }
348
349   //
350
// LexicalHandler support. Not all SAX2 filters support these events
351
// but we may want to pass them through when they exist...
352
//
353
// %REVIEW% These do NOT currently affect the eventcounter; I'm asserting
354
// that they're rare enough that it makes little or no sense to
355
// pause after them. As such, it may make more sense for folks who
356
// actually want to use them to register directly with the filter.
357
// But I want 'em here for now, to remind us to recheck this assertion!
358
//
359
public void comment(char[] ch, int start, int length)
360        throws org.xml.sax.SAXException JavaDoc
361   {
362     if(null!=clientLexicalHandler)
363       clientLexicalHandler.comment(ch,start,length);
364   }
365   public void endCDATA()
366        throws org.xml.sax.SAXException JavaDoc
367   {
368     if(null!=clientLexicalHandler)
369       clientLexicalHandler.endCDATA();
370   }
371   public void endDTD()
372        throws org.xml.sax.SAXException JavaDoc
373   {
374     if(null!=clientLexicalHandler)
375       clientLexicalHandler.endDTD();
376   }
377   public void endEntity(java.lang.String JavaDoc name)
378        throws org.xml.sax.SAXException JavaDoc
379   {
380     if(null!=clientLexicalHandler)
381       clientLexicalHandler.endEntity(name);
382   }
383   public void startCDATA()
384        throws org.xml.sax.SAXException JavaDoc
385   {
386     if(null!=clientLexicalHandler)
387       clientLexicalHandler.startCDATA();
388   }
389   public void startDTD(java.lang.String JavaDoc name, java.lang.String JavaDoc publicId,
390       java.lang.String JavaDoc systemId)
391        throws org.xml.sax.SAXException JavaDoc
392   {
393     if(null!=clientLexicalHandler)
394       clientLexicalHandler. startDTD(name, publicId, systemId);
395   }
396   public void startEntity(java.lang.String JavaDoc name)
397        throws org.xml.sax.SAXException JavaDoc
398   {
399     if(null!=clientLexicalHandler)
400       clientLexicalHandler.startEntity(name);
401   }
402
403   //
404
// DTDHandler support.
405

406   public void notationDecl(String JavaDoc a, String JavaDoc b, String JavaDoc c) throws SAXException JavaDoc
407   {
408     if(null!=clientDTDHandler)
409         clientDTDHandler.notationDecl(a,b,c);
410   }
411   public void unparsedEntityDecl(String JavaDoc a, String JavaDoc b, String JavaDoc c, String JavaDoc d) throws SAXException JavaDoc
412   {
413     if(null!=clientDTDHandler)
414         clientDTDHandler.unparsedEntityDecl(a,b,c,d);
415   }
416   
417   //
418
// ErrorHandler support.
419
//
420
// PROBLEM: Xerces is apparently _not_ calling the ErrorHandler for
421
// exceptions thrown by the ContentHandler, which prevents us from
422
// handling this properly when running in filtering mode with Xerces
423
// as our event source. It's unclear whether this is a Xerces bug
424
// or a SAX design flaw.
425
//
426
// %REVIEW% Current solution: In filtering mode, it is REQUIRED that
427
// event source make sure this method is invoked if the event stream
428
// abends before endDocument is delivered. If that means explicitly calling
429
// us in the exception handling code because it won't be delivered as part
430
// of the normal SAX ErrorHandler stream, that's fine; Not Our Problem.
431
//
432
public void error(SAXParseException JavaDoc exception) throws SAXException JavaDoc
433   {
434     if(null!=clientErrorHandler)
435       clientErrorHandler.error(exception);
436   }
437   
438   public void fatalError(SAXParseException JavaDoc exception) throws SAXException JavaDoc
439   {
440     // EXCEPTION: In this case we need to run the event BEFORE we yield --
441
// just as with endDocument, this terminates the event stream.
442
if(null!=clientErrorHandler)
443       clientErrorHandler.error(exception);
444
445     eventcounter=0;
446     co_yield(false);
447
448   }
449   
450   public void warning(SAXParseException JavaDoc exception) throws SAXException JavaDoc
451   {
452     if(null!=clientErrorHandler)
453       clientErrorHandler.error(exception);
454   }
455   
456
457   //
458
// coroutine support
459
//
460

461   public int getSourceCoroutineID() {
462     return fSourceCoroutineID;
463   }
464   public int getControllerCoroutineID() {
465     return fControllerCoroutineID;
466   }
467
468   /** @return the CoroutineManager this CoroutineFilter object is bound to.
469    * If you're using the do...() methods, applications should only
470    * need to talk to the CoroutineManager once, to obtain the
471    * application's Coroutine ID.
472    * */

473   public CoroutineManager getCoroutineManager()
474   {
475     return fCoroutineManager;
476   }
477
478   /** <p>In the SAX delegation code, I've inlined the count-down in
479    * the hope of encouraging compilers to deliver better
480    * performance. However, if we subclass (eg to directly connect the
481    * output to a DTM builder), that would require calling super in
482    * order to run that logic... which seems inelegant. Hence this
483    * routine for the convenience of subclasses: every [frequency]
484    * invocations, issue a co_yield.</p>
485    *
486    * @param moreExepected Should always be true unless this is being called
487    * at the end of endDocument() handling.
488    * */

489   protected void count_and_yield(boolean moreExpected) throws SAXException JavaDoc
490   {
491     if(!moreExpected) eventcounter=0;
492     
493     if(--eventcounter<=0)
494       {
495         co_yield(true);
496         eventcounter=frequency;
497       }
498   }
499
500   /**
501    * co_entry_pause is called in startDocument() before anything else
502    * happens. It causes the filter to wait for a "go ahead" request
503    * from the controller before delivering any events. Note that
504    * the very first thing the controller tells us may be "I don't
505    * need events after all"!
506    */

507   private void co_entry_pause() throws SAXException JavaDoc
508   {
509     if(fCoroutineManager==null)
510     {
511       // Nobody called init()? Do it now...
512
init(null,-1,-1);
513     }
514
515     try
516     {
517       Object JavaDoc arg=fCoroutineManager.co_entry_pause(fSourceCoroutineID);
518       if(arg==Boolean.FALSE)
519         co_yield(false);
520     }
521     catch(NoSuchMethodException JavaDoc e)
522     {
523       // Coroutine system says we haven't registered. That's an
524
// application coding error, and is unrecoverable.
525
if(DEBUG) e.printStackTrace();
526       throw new SAXException JavaDoc(e);
527     }
528   }
529
530   /**
531    * Co_Yield handles coroutine interactions while a parse is in progress.
532    *
533    * When moreRemains==true, we are pausing after delivering events, to
534    * ask if more are needed. We will resume the controller thread with
535    * co_resume(Boolean.TRUE, ...)
536    * When control is passed back it may indicate
537    * Boolean.TRUE indication to continue delivering events
538    * Boolean.FALSE indication to discontinue events and shut down.
539    *
540    * When moreRemains==false, we shut down immediately without asking the
541    * controller's permission. Normally this means end of document has been
542    * reached.
543    *
544    * Shutting down a IncrementalSAXSource_Filter requires terminating the incoming
545    * SAX event stream. If we are in control of that stream (if it came
546    * from an XMLReader passed to our startReader() method), we can do so
547    * very quickly by throwing a reserved exception to it. If the stream is
548    * coming from another source, we can't do that because its caller may
549    * not be prepared for this "normal abnormal exit", and instead we put
550    * ourselves in a "spin" mode where events are discarded.
551    */

552   private void co_yield(boolean moreRemains) throws SAXException JavaDoc
553   {
554     // Horrendous kluge to run filter to completion. See below.
555
if(fNoMoreEvents)
556       return;
557
558     try // Coroutine manager might throw no-such.
559
{
560       Object JavaDoc arg=Boolean.FALSE;
561       if(moreRemains)
562       {
563         // Yield control, resume parsing when done
564
arg = fCoroutineManager.co_resume(Boolean.TRUE, fSourceCoroutineID,
565                                           fControllerCoroutineID);
566         
567       }
568
569       // If we're at end of document or were told to stop early
570
if(arg==Boolean.FALSE)
571       {
572         fNoMoreEvents=true;
573         
574         if(fXMLReader!=null) // Running under startParseThread()
575
throw new StopException(); // We'll co_exit from there.
576

577         // Yield control. We do NOT expect anyone to ever ask us again.
578
fCoroutineManager.co_exit_to(Boolean.FALSE, fSourceCoroutineID,
579                                      fControllerCoroutineID);
580       }
581     }
582     catch(NoSuchMethodException JavaDoc e)
583     {
584       // Shouldn't happen unless we've miscoded our coroutine logic
585
// "Shut down the garbage smashers on the detention level!"
586
fNoMoreEvents=true;
587       fCoroutineManager.co_exit(fSourceCoroutineID);
588       throw new SAXException JavaDoc(e);
589     }
590   }
591
592   //
593
// Convenience: Run an XMLReader in a thread
594
//
595

596   /** Launch a thread that will run an XMLReader's parse() operation within
597    * a thread, feeding events to this IncrementalSAXSource_Filter. Mostly a convenience
598    * routine, but has the advantage that -- since we invoked parse() --
599    * we can halt parsing quickly via a StopException rather than waiting
600    * for the SAX stream to end by itself.
601    *
602    * @throws SAXException is parse thread is already in progress
603    * or parsing can not be started.
604    * */

605   public void startParse(InputSource JavaDoc source) throws SAXException JavaDoc
606   {
607     if(fNoMoreEvents)
608       throw new SAXException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_INCRSAXSRCFILTER_NOT_RESTARTABLE, null)); //"IncrmentalSAXSource_Filter not currently restartable.");
609
if(fXMLReader==null)
610       throw new SAXException JavaDoc(XMLMessages.createXMLMessage(XMLErrorResources.ER_XMLRDR_NOT_BEFORE_STARTPARSE, null)); //"XMLReader not before startParse request");
611

612     fXMLReaderInputSource=source;
613     
614     // Xalan thread pooling...
615
// com.sun.org.apache.xalan.internal.transformer.TransformerImpl.runTransformThread(this);
616
ThreadControllerWrapper.runThread(this, -1);
617   }
618   
619   /* Thread logic to support startParseThread()
620    */

621   public void run()
622   {
623     // Guard against direct invocation of start().
624
if(fXMLReader==null) return;
625
626     if(DEBUG)System.out.println("IncrementalSAXSource_Filter parse thread launched");
627
628     // Initially assume we'll run successfully.
629
Object JavaDoc arg=Boolean.FALSE;
630
631     // For the duration of this operation, all coroutine handshaking
632
// will occur in the co_yield method. That's the nice thing about
633
// coroutines; they give us a way to hand off control from the
634
// middle of a synchronous method.
635
try
636     {
637       fXMLReader.parse(fXMLReaderInputSource);
638     }
639     catch(IOException JavaDoc ex)
640     {
641       arg=ex;
642     }
643     catch(StopException ex)
644     {
645       // Expected and harmless
646
if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
647     }
648     catch (SAXException JavaDoc ex)
649     {
650       Exception JavaDoc inner=ex.getException();
651       if(inner instanceof StopException){
652         // Expected and harmless
653
if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
654       }
655       else
656       {
657         // Unexpected malfunction
658
if(DEBUG)
659         {
660           System.out.println("Active IncrementalSAXSource_Filter UNEXPECTED SAX exception: "+inner);
661           inner.printStackTrace();
662         }
663         arg=ex;
664       }
665     } // end parse
666

667     // Mark as no longer running in thread.
668
fXMLReader=null;
669
670     try
671     {
672       // Mark as done and yield control to the controller coroutine
673
fNoMoreEvents=true;
674       fCoroutineManager.co_exit_to(arg, fSourceCoroutineID,
675                                    fControllerCoroutineID);
676     }
677     catch(java.lang.NoSuchMethodException JavaDoc e)
678     {
679       // Shouldn't happen unless we've miscoded our coroutine logic
680
// "CPO, shut down the garbage smashers on the detention level!"
681
e.printStackTrace(System.err);
682       fCoroutineManager.co_exit(fSourceCoroutineID);
683     }
684   }
685
686   /** Used to quickly terminate parse when running under a
687       startParse() thread. Only its type is important. */

688   class StopException extends RuntimeException JavaDoc
689   {
690   }
691
692   /** deliverMoreNodes() is a simple API which tells the coroutine
693    * parser that we need more nodes. This is intended to be called
694    * from one of our partner routines, and serves to encapsulate the
695    * details of how incremental parsing has been achieved.
696    *
697    * @param parsemore If true, tells the incremental filter to generate
698    * another chunk of output. If false, tells the filter that we're
699    * satisfied and it can terminate parsing of this document.
700    *
701    * @return Boolean.TRUE if there may be more events available by invoking
702    * deliverMoreNodes() again. Boolean.FALSE if parsing has run to completion (or been
703    * terminated by deliverMoreNodes(false). Or an exception object if something
704    * malfunctioned. %REVIEW% We _could_ actually throw the exception, but
705    * that would require runinng deliverMoreNodes() in a try/catch... and for many
706    * applications, exception will be simply be treated as "not TRUE" in
707    * any case.
708    * */

709   public Object JavaDoc deliverMoreNodes(boolean parsemore)
710   {
711     // If parsing is already done, we can immediately say so
712
if(fNoMoreEvents)
713       return Boolean.FALSE;
714
715     try
716     {
717       Object JavaDoc result =
718         fCoroutineManager.co_resume(parsemore?Boolean.TRUE:Boolean.FALSE,
719                                     fControllerCoroutineID, fSourceCoroutineID);
720       if(result==Boolean.FALSE)
721         fCoroutineManager.co_exit(fControllerCoroutineID);
722
723       return result;
724     }
725       
726     // SHOULD NEVER OCCUR, since the coroutine number and coroutine manager
727
// are those previously established for this IncrementalSAXSource_Filter...
728
// So I'm just going to return it as a parsing exception, for now.
729
catch(NoSuchMethodException JavaDoc e)
730       {
731         return e;
732       }
733   }
734   
735
736   //================================================================
737
/** Simple unit test. Attempt coroutine parsing of document indicated
738    * by first argument (as a URI), report progress.
739    */

740     /*
741   public static void _main(String args[])
742   {
743     System.out.println("Starting...");
744
745     org.xml.sax.XMLReader theSAXParser=
746       new com.sun.org.apache.xerces.internal.parsers.SAXParser();
747   
748
749     for(int arg=0;arg<args.length;++arg)
750     {
751       // The filter is not currently designed to be restartable
752       // after a parse has ended. Generate a new one each time.
753       IncrementalSAXSource_Filter filter=
754         new IncrementalSAXSource_Filter();
755       // Use a serializer as our sample output
756       com.sun.org.apache.xml.internal.serialize.XMLSerializer trace;
757       trace=new com.sun.org.apache.xml.internal.serialize.XMLSerializer(System.out,null);
758       filter.setContentHandler(trace);
759       filter.setLexicalHandler(trace);
760
761       try
762       {
763         InputSource source = new InputSource(args[arg]);
764         Object result=null;
765         boolean more=true;
766
767         // init not issued; we _should_ automagically Do The Right Thing
768
769         // Bind parser, kick off parsing in a thread
770         filter.setXMLReader(theSAXParser);
771         filter.startParse(source);
772       
773         for(result = filter.deliverMoreNodes(more);
774             (result instanceof Boolean && ((Boolean)result)==Boolean.TRUE);
775             result = filter.deliverMoreNodes(more))
776         {
777           System.out.println("\nSome parsing successful, trying more.\n");
778           
779           // Special test: Terminate parsing early.
780           if(arg+1<args.length && "!".equals(args[arg+1]))
781           {
782             ++arg;
783             more=false;
784           }
785           
786         }
787       
788         if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
789         {
790           System.out.println("\nFilter ended (EOF or on request).\n");
791         }
792         else if (result == null) {
793           System.out.println("\nUNEXPECTED: Filter says shut down prematurely.\n");
794         }
795         else if (result instanceof Exception) {
796           System.out.println("\nFilter threw exception:");
797           ((Exception)result).printStackTrace();
798         }
799       
800       }
801       catch(SAXException e)
802       {
803         e.printStackTrace();
804       }
805     } // end for
806   }
807     */

808 } // class IncrementalSAXSource_Filter
809
Popular Tags