Source Code Cross Referenced for IncrementalSAXSource_Filter.java in  » XML » xalan » org » apache » xml » dtm » ref » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML » xalan » org.apache.xml.dtm.ref 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright 1999-2004 The Apache Software Foundation.
003:         *
004:         * Licensed under the Apache License, Version 2.0 (the "License");
005:         * you may not use this file except in compliance with the License.
006:         * You may obtain a copy of the License at
007:         *
008:         *     http://www.apache.org/licenses/LICENSE-2.0
009:         *
010:         * Unless required by applicable law or agreed to in writing, software
011:         * distributed under the License is distributed on an "AS IS" BASIS,
012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013:         * See the License for the specific language governing permissions and
014:         * limitations under the License.
015:         */
016:        /*
017:         * $Id: IncrementalSAXSource_Filter.java,v 1.12 2004/08/17 18:57:21 jycli Exp $
018:         */
019:
020:        package org.apache.xml.dtm.ref;
021:
022:        import java.io.IOException;
023:
024:        import org.apache.xml.res.XMLErrorResources;
025:        import org.apache.xml.res.XMLMessages;
026:        import org.apache.xml.utils.ThreadControllerWrapper;
027:
028:        import org.xml.sax.Attributes;
029:        import org.xml.sax.ContentHandler;
030:        import org.xml.sax.DTDHandler;
031:        import org.xml.sax.ErrorHandler;
032:        import org.xml.sax.InputSource;
033:        import org.xml.sax.Locator;
034:        import org.xml.sax.SAXException;
035:        import org.xml.sax.SAXNotRecognizedException;
036:        import org.xml.sax.SAXNotSupportedException;
037:        import org.xml.sax.SAXParseException;
038:        import org.xml.sax.XMLReader;
039:        import org.xml.sax.ext.LexicalHandler;
040:
041:        /** <p>IncrementalSAXSource_Filter implements IncrementalSAXSource, using a
042:         * standard SAX2 event source as its input and parcelling out those
043:         * events gradually in reponse to deliverMoreNodes() requests.  Output from the
044:         * filter will be passed along to a SAX handler registered as our
045:         * listener, but those callbacks will pass through a counting stage
046:         * which periodically yields control back to the controller coroutine.
047:         * </p>
048:         *
049:         * <p>%REVIEW%: This filter is not currenly intended to be reusable
050:         * for parsing additional streams/documents. We may want to consider
051:         * making it resettable at some point in the future. But it's a 
052:         * small object, so that'd be mostly a convenience issue; the cost
053:         * of allocating each time is trivial compared to the cost of processing
054:         * any nontrival stream.</p>
055:         *
056:         * <p>For a brief usage example, see the unit-test main() method.</p>
057:         *
058:         * <p>This is a simplification of the old CoroutineSAXParser, focusing
059:         * specifically on filtering. The resulting controller protocol is _far_
060:         * simpler and less error-prone; the only controller operation is deliverMoreNodes(),
061:         * and the only requirement is that deliverMoreNodes(false) be called if you want to
062:         * discard the rest of the stream and the previous deliverMoreNodes() didn't return
063:         * false.
064:         * */
065:        public class IncrementalSAXSource_Filter implements 
066:                IncrementalSAXSource, ContentHandler, DTDHandler,
067:                LexicalHandler, ErrorHandler, Runnable {
068:            boolean DEBUG = false; //Internal status report
069:
070:            //
071:            // Data
072:            //
073:            private CoroutineManager fCoroutineManager = null;
074:            private int fControllerCoroutineID = -1;
075:            private int fSourceCoroutineID = -1;
076:
077:            private ContentHandler clientContentHandler = null; // %REVIEW% support multiple?
078:            private LexicalHandler clientLexicalHandler = null; // %REVIEW% support multiple?
079:            private DTDHandler clientDTDHandler = null; // %REVIEW% support multiple?
080:            private ErrorHandler clientErrorHandler = null; // %REVIEW% support multiple?
081:            private int eventcounter;
082:            private int frequency = 5;
083:
084:            // Flag indicating that no more events should be delivered -- either
085:            // because input stream ran to completion (endDocument), or because
086:            // the user requested an early stop via deliverMoreNodes(false).
087:            private boolean fNoMoreEvents = false;
088:
089:            // Support for startParse()
090:            private XMLReader fXMLReader = null;
091:            private InputSource fXMLReaderInputSource = null;
092:
093:            //
094:            // Constructors
095:            //
096:
097:            public IncrementalSAXSource_Filter() {
098:                this .init(new CoroutineManager(), -1, -1);
099:            }
100:
101:            /** Create a IncrementalSAXSource_Filter which is not yet bound to a specific
102:             * SAX event source.
103:             * */
104:            public IncrementalSAXSource_Filter(CoroutineManager co,
105:                    int controllerCoroutineID) {
106:                this .init(co, controllerCoroutineID, -1);
107:            }
108:
109:            //
110:            // Factories
111:            //
112:            static public IncrementalSAXSource createIncrementalSAXSource(
113:                    CoroutineManager co, int controllerCoroutineID) {
114:                return new IncrementalSAXSource_Filter(co,
115:                        controllerCoroutineID);
116:            }
117:
118:            //
119:            // Public methods
120:            //
121:
122:            public void init(CoroutineManager co, int controllerCoroutineID,
123:                    int sourceCoroutineID) {
124:                if (co == null)
125:                    co = new CoroutineManager();
126:                fCoroutineManager = co;
127:                fControllerCoroutineID = co
128:                        .co_joinCoroutineSet(controllerCoroutineID);
129:                fSourceCoroutineID = co.co_joinCoroutineSet(sourceCoroutineID);
130:                if (fControllerCoroutineID == -1 || fSourceCoroutineID == -1)
131:                    throw new RuntimeException(XMLMessages.createXMLMessage(
132:                            XMLErrorResources.ER_COJOINROUTINESET_FAILED, null)); //"co_joinCoroutineSet() failed");
133:
134:                fNoMoreEvents = false;
135:                eventcounter = frequency;
136:            }
137:
138:            /** Bind our input streams to an XMLReader.
139:             *
140:             * Just a convenience routine; obviously you can explicitly register
141:             * this as a listener with the same effect.
142:             * */
143:            public void setXMLReader(XMLReader eventsource) {
144:                fXMLReader = eventsource;
145:                eventsource.setContentHandler(this );
146:                eventsource.setDTDHandler(this );
147:                eventsource.setErrorHandler(this ); // to report fatal errors in filtering mode
148:
149:                // Not supported by all SAX2 filters:
150:                try {
151:                    eventsource.setProperty(
152:                            "http://xml.org/sax/properties/lexical-handler",
153:                            this );
154:                } catch (SAXNotRecognizedException e) {
155:                    // Nothing we can do about it
156:                } catch (SAXNotSupportedException e) {
157:                    // Nothing we can do about it
158:                }
159:
160:                // Should we also bind as other varieties of handler?
161:                // (DTDHandler and so on)
162:            }
163:
164:            // Register a content handler for us to output to
165:            public void setContentHandler(ContentHandler handler) {
166:                clientContentHandler = handler;
167:            }
168:
169:            // Register a DTD handler for us to output to
170:            public void setDTDHandler(DTDHandler handler) {
171:                clientDTDHandler = handler;
172:            }
173:
174:            // Register a lexical handler for us to output to
175:            // Not all filters support this...
176:            // ??? Should we register directly on the filter?
177:            // NOTE NAME -- subclassing issue in the Xerces version
178:            public void setLexicalHandler(LexicalHandler handler) {
179:                clientLexicalHandler = handler;
180:            }
181:
182:            // Register an error handler for us to output to
183:            // NOTE NAME -- subclassing issue in the Xerces version
184:            public void setErrHandler(ErrorHandler handler) {
185:                clientErrorHandler = handler;
186:            }
187:
188:            // Set the number of events between resumes of our coroutine
189:            // Immediately resets number of events before _next_ resume as well.
190:            public void setReturnFrequency(int events) {
191:                if (events < 1)
192:                    events = 1;
193:                frequency = eventcounter = events;
194:            }
195:
196:            //
197:            // ContentHandler methods
198:            // These  pass the data to our client ContentHandler...
199:            // but they also count the number of events passing through,
200:            // and resume our coroutine each time that counter hits zero and
201:            // is reset.
202:            //
203:            // Note that for everything except endDocument and fatalError, we do the count-and-yield
204:            // BEFORE passing the call along. I'm hoping that this will encourage JIT
205:            // compilers to realize that these are tail-calls, reducing the expense of
206:            // the additional layer of data flow.
207:            //
208:            // %REVIEW% Glenn suggests that pausing after endElement, endDocument,
209:            // and characters may be sufficient. I actually may not want to
210:            // stop after characters, since in our application these wind up being
211:            // concatenated before they're processed... but that risks huge blocks of
212:            // text causing greater than usual readahead. (Unlikely? Consider the
213:            // possibility of a large base-64 block in a SOAP stream.)
214:            //
215:            public void characters(char[] ch, int start, int length)
216:                    throws org.xml.sax.SAXException {
217:                if (--eventcounter <= 0) {
218:                    co_yield(true);
219:                    eventcounter = frequency;
220:                }
221:                if (clientContentHandler != null)
222:                    clientContentHandler.characters(ch, start, length);
223:            }
224:
225:            public void endDocument() throws org.xml.sax.SAXException {
226:                // EXCEPTION: In this case we need to run the event BEFORE we yield.
227:                if (clientContentHandler != null)
228:                    clientContentHandler.endDocument();
229:
230:                eventcounter = 0;
231:                co_yield(false);
232:            }
233:
234:            public void endElement(java.lang.String namespaceURI,
235:                    java.lang.String localName, java.lang.String qName)
236:                    throws org.xml.sax.SAXException {
237:                if (--eventcounter <= 0) {
238:                    co_yield(true);
239:                    eventcounter = frequency;
240:                }
241:                if (clientContentHandler != null)
242:                    clientContentHandler.endElement(namespaceURI, localName,
243:                            qName);
244:            }
245:
246:            public void endPrefixMapping(java.lang.String prefix)
247:                    throws org.xml.sax.SAXException {
248:                if (--eventcounter <= 0) {
249:                    co_yield(true);
250:                    eventcounter = frequency;
251:                }
252:                if (clientContentHandler != null)
253:                    clientContentHandler.endPrefixMapping(prefix);
254:            }
255:
256:            public void ignorableWhitespace(char[] ch, int start, int length)
257:                    throws org.xml.sax.SAXException {
258:                if (--eventcounter <= 0) {
259:                    co_yield(true);
260:                    eventcounter = frequency;
261:                }
262:                if (clientContentHandler != null)
263:                    clientContentHandler.ignorableWhitespace(ch, start, length);
264:            }
265:
266:            public void processingInstruction(java.lang.String target,
267:                    java.lang.String data) throws org.xml.sax.SAXException {
268:                if (--eventcounter <= 0) {
269:                    co_yield(true);
270:                    eventcounter = frequency;
271:                }
272:                if (clientContentHandler != null)
273:                    clientContentHandler.processingInstruction(target, data);
274:            }
275:
276:            public void setDocumentLocator(Locator locator) {
277:                if (--eventcounter <= 0) {
278:                    // This can cause a hang.  -sb
279:                    // co_yield(true);
280:                    eventcounter = frequency;
281:                }
282:                if (clientContentHandler != null)
283:                    clientContentHandler.setDocumentLocator(locator);
284:            }
285:
286:            public void skippedEntity(java.lang.String name)
287:                    throws org.xml.sax.SAXException {
288:                if (--eventcounter <= 0) {
289:                    co_yield(true);
290:                    eventcounter = frequency;
291:                }
292:                if (clientContentHandler != null)
293:                    clientContentHandler.skippedEntity(name);
294:            }
295:
296:            public void startDocument() throws org.xml.sax.SAXException {
297:                co_entry_pause();
298:
299:                // Otherwise, begin normal event delivery
300:                if (--eventcounter <= 0) {
301:                    co_yield(true);
302:                    eventcounter = frequency;
303:                }
304:                if (clientContentHandler != null)
305:                    clientContentHandler.startDocument();
306:            }
307:
308:            public void startElement(java.lang.String namespaceURI,
309:                    java.lang.String localName, java.lang.String qName,
310:                    Attributes atts) throws org.xml.sax.SAXException {
311:                if (--eventcounter <= 0) {
312:                    co_yield(true);
313:                    eventcounter = frequency;
314:                }
315:                if (clientContentHandler != null)
316:                    clientContentHandler.startElement(namespaceURI, localName,
317:                            qName, atts);
318:            }
319:
320:            public void startPrefixMapping(java.lang.String prefix,
321:                    java.lang.String uri) throws org.xml.sax.SAXException {
322:                if (--eventcounter <= 0) {
323:                    co_yield(true);
324:                    eventcounter = frequency;
325:                }
326:                if (clientContentHandler != null)
327:                    clientContentHandler.startPrefixMapping(prefix, uri);
328:            }
329:
330:            //
331:            // LexicalHandler support. Not all SAX2 filters support these events
332:            // but we may want to pass them through when they exist...
333:            //
334:            // %REVIEW% These do NOT currently affect the eventcounter; I'm asserting
335:            // that they're rare enough that it makes little or no sense to
336:            // pause after them. As such, it may make more sense for folks who
337:            // actually want to use them to register directly with the filter.
338:            // But I want 'em here for now, to remind us to recheck this assertion!
339:            //
340:            public void comment(char[] ch, int start, int length)
341:                    throws org.xml.sax.SAXException {
342:                if (null != clientLexicalHandler)
343:                    clientLexicalHandler.comment(ch, start, length);
344:            }
345:
346:            public void endCDATA() throws org.xml.sax.SAXException {
347:                if (null != clientLexicalHandler)
348:                    clientLexicalHandler.endCDATA();
349:            }
350:
351:            public void endDTD() throws org.xml.sax.SAXException {
352:                if (null != clientLexicalHandler)
353:                    clientLexicalHandler.endDTD();
354:            }
355:
356:            public void endEntity(java.lang.String name)
357:                    throws org.xml.sax.SAXException {
358:                if (null != clientLexicalHandler)
359:                    clientLexicalHandler.endEntity(name);
360:            }
361:
362:            public void startCDATA() throws org.xml.sax.SAXException {
363:                if (null != clientLexicalHandler)
364:                    clientLexicalHandler.startCDATA();
365:            }
366:
367:            public void startDTD(java.lang.String name,
368:                    java.lang.String publicId, java.lang.String systemId)
369:                    throws org.xml.sax.SAXException {
370:                if (null != clientLexicalHandler)
371:                    clientLexicalHandler.startDTD(name, publicId, systemId);
372:            }
373:
374:            public void startEntity(java.lang.String name)
375:                    throws org.xml.sax.SAXException {
376:                if (null != clientLexicalHandler)
377:                    clientLexicalHandler.startEntity(name);
378:            }
379:
380:            //
381:            // DTDHandler support.
382:
383:            public void notationDecl(String a, String b, String c)
384:                    throws SAXException {
385:                if (null != clientDTDHandler)
386:                    clientDTDHandler.notationDecl(a, b, c);
387:            }
388:
389:            public void unparsedEntityDecl(String a, String b, String c,
390:                    String d) throws SAXException {
391:                if (null != clientDTDHandler)
392:                    clientDTDHandler.unparsedEntityDecl(a, b, c, d);
393:            }
394:
395:            //
396:            // ErrorHandler support.
397:            //
398:            // PROBLEM: Xerces is apparently _not_ calling the ErrorHandler for
399:            // exceptions thrown by the ContentHandler, which prevents us from
400:            // handling this properly when running in filtering mode with Xerces
401:            // as our event source.  It's unclear whether this is a Xerces bug
402:            // or a SAX design flaw.
403:            // 
404:            // %REVIEW% Current solution: In filtering mode, it is REQUIRED that
405:            // event source make sure this method is invoked if the event stream
406:            // abends before endDocument is delivered. If that means explicitly calling
407:            // us in the exception handling code because it won't be delivered as part
408:            // of the normal SAX ErrorHandler stream, that's fine; Not Our Problem.
409:            //
410:            public void error(SAXParseException exception) throws SAXException {
411:                if (null != clientErrorHandler)
412:                    clientErrorHandler.error(exception);
413:            }
414:
415:            public void fatalError(SAXParseException exception)
416:                    throws SAXException {
417:                // EXCEPTION: In this case we need to run the event BEFORE we yield --
418:                // just as with endDocument, this terminates the event stream.
419:                if (null != clientErrorHandler)
420:                    clientErrorHandler.error(exception);
421:
422:                eventcounter = 0;
423:                co_yield(false);
424:
425:            }
426:
427:            public void warning(SAXParseException exception)
428:                    throws SAXException {
429:                if (null != clientErrorHandler)
430:                    clientErrorHandler.error(exception);
431:            }
432:
433:            //
434:            // coroutine support
435:            //
436:
437:            public int getSourceCoroutineID() {
438:                return fSourceCoroutineID;
439:            }
440:
441:            public int getControllerCoroutineID() {
442:                return fControllerCoroutineID;
443:            }
444:
445:            /** @return the CoroutineManager this CoroutineFilter object is bound to.
446:             * If you're using the do...() methods, applications should only
447:             * need to talk to the CoroutineManager once, to obtain the
448:             * application's Coroutine ID.
449:             * */
450:            public CoroutineManager getCoroutineManager() {
451:                return fCoroutineManager;
452:            }
453:
454:            /** <p>In the SAX delegation code, I've inlined the count-down in
455:             * the hope of encouraging compilers to deliver better
456:             * performance. However, if we subclass (eg to directly connect the
457:             * output to a DTM builder), that would require calling super in
458:             * order to run that logic... which seems inelegant.  Hence this
459:             * routine for the convenience of subclasses: every [frequency]
460:             * invocations, issue a co_yield.</p>
461:             *
462:             * @param moreExepected Should always be true unless this is being called
463:             * at the end of endDocument() handling.
464:             * */
465:            protected void count_and_yield(boolean moreExpected)
466:                    throws SAXException {
467:                if (!moreExpected)
468:                    eventcounter = 0;
469:
470:                if (--eventcounter <= 0) {
471:                    co_yield(true);
472:                    eventcounter = frequency;
473:                }
474:            }
475:
476:            /**
477:             * co_entry_pause is called in startDocument() before anything else
478:             * happens. It causes the filter to wait for a "go ahead" request
479:             * from the controller before delivering any events. Note that
480:             * the very first thing the controller tells us may be "I don't
481:             * need events after all"!
482:             */
483:            private void co_entry_pause() throws SAXException {
484:                if (fCoroutineManager == null) {
485:                    // Nobody called init()? Do it now...
486:                    init(null, -1, -1);
487:                }
488:
489:                try {
490:                    Object arg = fCoroutineManager
491:                            .co_entry_pause(fSourceCoroutineID);
492:                    if (arg == Boolean.FALSE)
493:                        co_yield(false);
494:                } catch (NoSuchMethodException e) {
495:                    // Coroutine system says we haven't registered. That's an
496:                    // application coding error, and is unrecoverable.
497:                    if (DEBUG)
498:                        e.printStackTrace();
499:                    throw new SAXException(e);
500:                }
501:            }
502:
503:            /**
504:             * Co_Yield handles coroutine interactions while a parse is in progress.
505:             *
506:             * When moreRemains==true, we are pausing after delivering events, to
507:             * ask if more are needed. We will resume the controller thread with 
508:             *   co_resume(Boolean.TRUE, ...)
509:             * When control is passed back it may indicate
510:             *      Boolean.TRUE    indication to continue delivering events
511:             *      Boolean.FALSE   indication to discontinue events and shut down.
512:             * 
513:             * When moreRemains==false, we shut down immediately without asking the
514:             * controller's permission. Normally this means end of document has been
515:             * reached.
516:             *
517:             * Shutting down a IncrementalSAXSource_Filter requires terminating the incoming
518:             * SAX event stream. If we are in control of that stream (if it came
519:             * from an XMLReader passed to our startReader() method), we can do so
520:             * very quickly by throwing a reserved exception to it. If the stream is
521:             * coming from another source, we can't do that because its caller may
522:             * not be prepared for this "normal abnormal exit", and instead we put
523:             * ourselves in a "spin" mode where events are discarded.
524:             */
525:            private void co_yield(boolean moreRemains) throws SAXException {
526:                // Horrendous kluge to run filter to completion. See below.
527:                if (fNoMoreEvents)
528:                    return;
529:
530:                try // Coroutine manager might throw no-such.
531:                {
532:                    Object arg = Boolean.FALSE;
533:                    if (moreRemains) {
534:                        // Yield control, resume parsing when done
535:                        arg = fCoroutineManager.co_resume(Boolean.TRUE,
536:                                fSourceCoroutineID, fControllerCoroutineID);
537:
538:                    }
539:
540:                    // If we're at end of document or were told to stop early
541:                    if (arg == Boolean.FALSE) {
542:                        fNoMoreEvents = true;
543:
544:                        if (fXMLReader != null) // Running under startParseThread()
545:                            throw new StopException(); // We'll co_exit from there.
546:
547:                        // Yield control. We do NOT expect anyone to ever ask us again.
548:                        fCoroutineManager.co_exit_to(Boolean.FALSE,
549:                                fSourceCoroutineID, fControllerCoroutineID);
550:                    }
551:                } catch (NoSuchMethodException e) {
552:                    // Shouldn't happen unless we've miscoded our coroutine logic
553:                    // "Shut down the garbage smashers on the detention level!"
554:                    fNoMoreEvents = true;
555:                    fCoroutineManager.co_exit(fSourceCoroutineID);
556:                    throw new SAXException(e);
557:                }
558:            }
559:
560:            //
561:            // Convenience: Run an XMLReader in a thread
562:            //
563:
564:            /** Launch a thread that will run an XMLReader's parse() operation within
565:             *  a thread, feeding events to this IncrementalSAXSource_Filter. Mostly a convenience
566:             *  routine, but has the advantage that -- since we invoked parse() --
567:             *  we can halt parsing quickly via a StopException rather than waiting
568:             *  for the SAX stream to end by itself.
569:             *
570:             * @throws SAXException is parse thread is already in progress
571:             * or parsing can not be started.
572:             * */
573:            public void startParse(InputSource source) throws SAXException {
574:                if (fNoMoreEvents)
575:                    throw new SAXException(
576:                            XMLMessages
577:                                    .createXMLMessage(
578:                                            XMLErrorResources.ER_INCRSAXSRCFILTER_NOT_RESTARTABLE,
579:                                            null)); //"IncrmentalSAXSource_Filter not currently restartable.");
580:                if (fXMLReader == null)
581:                    throw new SAXException(XMLMessages.createXMLMessage(
582:                            XMLErrorResources.ER_XMLRDR_NOT_BEFORE_STARTPARSE,
583:                            null)); //"XMLReader not before startParse request");
584:
585:                fXMLReaderInputSource = source;
586:
587:                // Xalan thread pooling...
588:                // org.apache.xalan.transformer.TransformerImpl.runTransformThread(this);
589:                ThreadControllerWrapper.runThread(this , -1);
590:            }
591:
592:            /* Thread logic to support startParseThread()
593:             */
594:            public void run() {
595:                // Guard against direct invocation of start().
596:                if (fXMLReader == null)
597:                    return;
598:
599:                if (DEBUG)
600:                    System.out
601:                            .println("IncrementalSAXSource_Filter parse thread launched");
602:
603:                // Initially assume we'll run successfully.
604:                Object arg = Boolean.FALSE;
605:
606:                // For the duration of this operation, all coroutine handshaking
607:                // will occur in the co_yield method. That's the nice thing about
608:                // coroutines; they give us a way to hand off control from the
609:                // middle of a synchronous method.
610:                try {
611:                    fXMLReader.parse(fXMLReaderInputSource);
612:                } catch (IOException ex) {
613:                    arg = ex;
614:                } catch (StopException ex) {
615:                    // Expected and harmless
616:                    if (DEBUG)
617:                        System.out
618:                                .println("Active IncrementalSAXSource_Filter normal stop exception");
619:                } catch (SAXException ex) {
620:                    Exception inner = ex.getException();
621:                    if (inner instanceof  StopException) {
622:                        // Expected and harmless
623:                        if (DEBUG)
624:                            System.out
625:                                    .println("Active IncrementalSAXSource_Filter normal stop exception");
626:                    } else {
627:                        // Unexpected malfunction
628:                        if (DEBUG) {
629:                            System.out
630:                                    .println("Active IncrementalSAXSource_Filter UNEXPECTED SAX exception: "
631:                                            + inner);
632:                            inner.printStackTrace();
633:                        }
634:                        arg = ex;
635:                    }
636:                } // end parse
637:
638:                // Mark as no longer running in thread.
639:                fXMLReader = null;
640:
641:                try {
642:                    // Mark as done and yield control to the controller coroutine
643:                    fNoMoreEvents = true;
644:                    fCoroutineManager.co_exit_to(arg, fSourceCoroutineID,
645:                            fControllerCoroutineID);
646:                } catch (java.lang.NoSuchMethodException e) {
647:                    // Shouldn't happen unless we've miscoded our coroutine logic
648:                    // "CPO, shut down the garbage smashers on the detention level!"
649:                    e.printStackTrace(System.err);
650:                    fCoroutineManager.co_exit(fSourceCoroutineID);
651:                }
652:            }
653:
654:            /** Used to quickly terminate parse when running under a
655:                startParse() thread. Only its type is important. */
656:            class StopException extends RuntimeException {
657:                static final long serialVersionUID = -1129245796185754956L;
658:            }
659:
660:            /** deliverMoreNodes() is a simple API which tells the coroutine
661:             * parser that we need more nodes.  This is intended to be called
662:             * from one of our partner routines, and serves to encapsulate the
663:             * details of how incremental parsing has been achieved.
664:             *
665:             * @param parsemore If true, tells the incremental filter to generate
666:             * another chunk of output. If false, tells the filter that we're
667:             * satisfied and it can terminate parsing of this document.
668:             *
669:             * @return Boolean.TRUE if there may be more events available by invoking
670:             * deliverMoreNodes() again. Boolean.FALSE if parsing has run to completion (or been
671:             * terminated by deliverMoreNodes(false). Or an exception object if something
672:             * malfunctioned. %REVIEW% We _could_ actually throw the exception, but
673:             * that would require runinng deliverMoreNodes() in a try/catch... and for many
674:             * applications, exception will be simply be treated as "not TRUE" in
675:             * any case.
676:             * */
677:            public Object deliverMoreNodes(boolean parsemore) {
678:                // If parsing is already done, we can immediately say so
679:                if (fNoMoreEvents)
680:                    return Boolean.FALSE;
681:
682:                try {
683:                    Object result = fCoroutineManager.co_resume(
684:                            parsemore ? Boolean.TRUE : Boolean.FALSE,
685:                            fControllerCoroutineID, fSourceCoroutineID);
686:                    if (result == Boolean.FALSE)
687:                        fCoroutineManager.co_exit(fControllerCoroutineID);
688:
689:                    return result;
690:                }
691:
692:                // SHOULD NEVER OCCUR, since the coroutine number and coroutine manager
693:                // are those previously established for this IncrementalSAXSource_Filter...
694:                // So I'm just going to return it as a parsing exception, for now.
695:                catch (NoSuchMethodException e) {
696:                    return e;
697:                }
698:            }
699:
700:            //================================================================
701:            /** Simple unit test. Attempt coroutine parsing of document indicated
702:             * by first argument (as a URI), report progress.
703:             */
704:            /*
705:            public static void main(String args[])
706:            {
707:            System.out.println("Starting...");
708:
709:            org.xml.sax.XMLReader theSAXParser=
710:              new org.apache.xerces.parsers.SAXParser();
711:            
712:
713:            for(int arg=0;arg<args.length;++arg)
714:            {
715:              // The filter is not currently designed to be restartable
716:              // after a parse has ended. Generate a new one each time.
717:              IncrementalSAXSource_Filter filter=
718:                new IncrementalSAXSource_Filter();
719:              // Use a serializer as our sample output
720:              org.apache.xml.serialize.XMLSerializer trace;
721:              trace=new org.apache.xml.serialize.XMLSerializer(System.out,null);
722:              filter.setContentHandler(trace);
723:              filter.setLexicalHandler(trace);
724:
725:              try
726:              {
727:                InputSource source = new InputSource(args[arg]);
728:                Object result=null;
729:                boolean more=true;
730:
731:                // init not issued; we _should_ automagically Do The Right Thing
732:
733:                // Bind parser, kick off parsing in a thread
734:                filter.setXMLReader(theSAXParser);
735:                filter.startParse(source);
736:              
737:                for(result = filter.deliverMoreNodes(more);
738:                    (result instanceof Boolean && ((Boolean)result)==Boolean.TRUE);
739:                    result = filter.deliverMoreNodes(more))
740:                {
741:                  System.out.println("\nSome parsing successful, trying more.\n");
742:                  
743:                  // Special test: Terminate parsing early.
744:                  if(arg+1<args.length && "!".equals(args[arg+1]))
745:                  {
746:                    ++arg;
747:                    more=false;
748:                  }
749:                  
750:                }
751:              
752:                if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
753:                {
754:                  System.out.println("\nFilter ended (EOF or on request).\n");
755:                }
756:                else if (result == null) {
757:                  System.out.println("\nUNEXPECTED: Filter says shut down prematurely.\n");
758:                }
759:                else if (result instanceof Exception) {
760:                  System.out.println("\nFilter threw exception:");
761:                  ((Exception)result).printStackTrace();
762:                }
763:              
764:              }
765:              catch(SAXException e)
766:              {
767:                e.printStackTrace();
768:              }
769:            } // end for
770:            }
771:             */
772:        } // class IncrementalSAXSource_Filter
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.