2 Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package gnu
.xml
.pipeline
;
40 import org
.xml
.sax
.Attributes
;
41 import org
.xml
.sax
.ContentHandler
;
42 import org
.xml
.sax
.DTDHandler
;
43 import org
.xml
.sax
.ErrorHandler
;
44 import org
.xml
.sax
.Locator
;
45 import org
.xml
.sax
.SAXException
;
46 import org
.xml
.sax
.SAXNotRecognizedException
;
47 import org
.xml
.sax
.ext
.DeclHandler
;
48 import org
.xml
.sax
.ext
.LexicalHandler
;
51 * Fans its events out to two other consumers, a "tee" filter stage in an
52 * event pipeline. Networks can be assembled with multiple output points.
54 * <p> Error handling should be simple if you remember that exceptions
55 * you throw will cancel later stages in that callback's pipeline, and
56 * generally the producer will stop if it sees such an exception. You
57 * may want to protect your pipeline against such backflows, making a
58 * kind of reverse filter (or valve?) so that certain exceptions thrown by
59 * your pipeline will caught and handled before the producer sees them.
60 * Just use a "try/catch" block, rememebering that really important
61 * cleanup tasks should be in "finally" clauses.
63 * <p> That issue isn't unique to "tee" consumers, but tee consumers have
64 * the additional twist that exceptions thrown by the first consumer
65 * will cause the second consumer not to see the callback (except for
66 * the endDocument callback, which signals state cleanup).
68 * @author David Brownell
70 final public class TeeConsumer
71 implements EventConsumer
,
72 ContentHandler
, DTDHandler
,
73 LexicalHandler
,DeclHandler
75 private EventConsumer first
, rest
;
77 // cached to minimize time overhead
78 private ContentHandler docFirst
, docRest
;
79 private DeclHandler declFirst
, declRest
;
80 private LexicalHandler lexFirst
, lexRest
;
84 * Constructs a consumer which sends all its events to the first
85 * consumer, and then the second one. If the first consumer throws
86 * an exception, the second one will not see the event which
87 * caused that exception to be reported.
89 * @param car The first consumer to get the events
90 * @param cdr The second consumer to get the events
92 public TeeConsumer (EventConsumer car
, EventConsumer cdr
)
94 if (car
== null || cdr
== null)
95 throw new NullPointerException ();
100 // Cache the handlers.
102 docFirst
= first
.getContentHandler ();
103 docRest
= rest
.getContentHandler ();
104 // DTD handler isn't cached (rarely needed)
108 declFirst
= (DeclHandler
) first
.getProperty (
109 EventFilter
.DECL_HANDLER
);
110 } catch (SAXException e
) {}
113 declRest
= (DeclHandler
) rest
.getProperty (
114 EventFilter
.DECL_HANDLER
);
115 } catch (SAXException e
) {}
119 lexFirst
= (LexicalHandler
) first
.getProperty (
120 EventFilter
.LEXICAL_HANDLER
);
121 } catch (SAXException e
) {}
124 lexRest
= (LexicalHandler
) rest
.getProperty (
125 EventFilter
.LEXICAL_HANDLER
);
126 } catch (SAXException e
) {}
131 * Constructs a pipeline, and is otherwise a shorthand for the
132 * two-consumer constructor for this class.
134 * @param first Description of the first pipeline to get events,
135 * which will be passed to {@link PipelineFactory#createPipeline}
136 * @param rest The second pipeline to get the events
138 // constructor used by PipelineFactory
139 public TeeConsumer (String first, EventConsumer rest)
142 this (PipelineFactory.createPipeline (first), rest);
146 /** Returns the first pipeline to get event calls. */
147 public EventConsumer
getFirst ()
150 /** Returns the second pipeline to get event calls. */
151 public EventConsumer
getRest ()
154 /** Returns the content handler being used. */
155 final public ContentHandler
getContentHandler ()
159 if (docFirst
== null)
164 /** Returns the dtd handler being used. */
165 final public DTDHandler
getDTDHandler ()
167 // not cached (hardly used)
168 if (rest
.getDTDHandler () == null)
169 return first
.getDTDHandler ();
170 if (first
.getDTDHandler () == null)
171 return rest
.getDTDHandler ();
175 /** Returns the declaration or lexical handler being used. */
176 final public Object
getProperty (String id
)
177 throws SAXNotRecognizedException
180 // in degenerate cases, we have no work to do.
182 Object firstProp
= null, restProp
= null;
184 try { firstProp
= first
.getProperty (id
); }
185 catch (SAXNotRecognizedException e
) { /* ignore */ }
186 try { restProp
= rest
.getProperty (id
); }
187 catch (SAXNotRecognizedException e
) { /* ignore */ }
189 if (restProp
== null)
191 if (firstProp
== null)
195 // we've got work to do; handle two builtin cases.
197 if (EventFilter
.DECL_HANDLER
.equals (id
))
199 if (EventFilter
.LEXICAL_HANDLER
.equals (id
))
203 // non-degenerate, handled by both consumers, but we don't know
204 // how to handle this.
206 throw new SAXNotRecognizedException ("can't tee: " + id
);
210 * Provides the error handler to both subsequent nodes of
213 public void setErrorHandler (ErrorHandler handler
)
215 first
.setErrorHandler (handler
);
216 rest
.setErrorHandler (handler
);
223 public void setDocumentLocator (Locator locator
)
225 // this call is not made by all parsers
226 docFirst
.setDocumentLocator (locator
);
227 docRest
.setDocumentLocator (locator
);
230 public void startDocument ()
233 docFirst
.startDocument ();
234 docRest
.startDocument ();
237 public void endDocument ()
241 docFirst
.endDocument ();
243 docRest
.endDocument ();
247 public void startPrefixMapping (String prefix
, String uri
)
250 docFirst
.startPrefixMapping (prefix
, uri
);
251 docRest
.startPrefixMapping (prefix
, uri
);
254 public void endPrefixMapping (String prefix
)
257 docFirst
.endPrefixMapping (prefix
);
258 docRest
.endPrefixMapping (prefix
);
261 public void skippedEntity (String name
)
264 docFirst
.skippedEntity (name
);
265 docRest
.skippedEntity (name
);
268 public void startElement (String uri
, String localName
,
269 String qName
, Attributes atts
)
272 docFirst
.startElement (uri
, localName
, qName
, atts
);
273 docRest
.startElement (uri
, localName
, qName
, atts
);
276 public void endElement (String uri
, String localName
, String qName
)
279 docFirst
.endElement (uri
, localName
, qName
);
280 docRest
.endElement (uri
, localName
, qName
);
283 public void processingInstruction (String target
, String data
)
286 docFirst
.processingInstruction (target
, data
);
287 docRest
.processingInstruction (target
, data
);
290 public void characters (char ch
[], int start
, int length
)
293 docFirst
.characters (ch
, start
, length
);
294 docRest
.characters (ch
, start
, length
);
297 public void ignorableWhitespace (char ch
[], int start
, int length
)
300 docFirst
.ignorableWhitespace (ch
, start
, length
);
301 docRest
.ignorableWhitespace (ch
, start
, length
);
308 public void notationDecl (String name
, String publicId
, String systemId
)
311 DTDHandler l1
= first
.getDTDHandler ();
312 DTDHandler l2
= rest
.getDTDHandler ();
314 l1
.notationDecl (name
, publicId
, systemId
);
315 l2
.notationDecl (name
, publicId
, systemId
);
318 public void unparsedEntityDecl (String name
,
319 String publicId
, String systemId
,
321 ) throws SAXException
323 DTDHandler l1
= first
.getDTDHandler ();
324 DTDHandler l2
= rest
.getDTDHandler ();
326 l1
.unparsedEntityDecl (name
, publicId
, systemId
, notationName
);
327 l2
.unparsedEntityDecl (name
, publicId
, systemId
, notationName
);
334 public void attributeDecl (String eName
, String aName
,
336 String mode
, String value
)
339 declFirst
.attributeDecl (eName
, aName
, type
, mode
, value
);
340 declRest
.attributeDecl (eName
, aName
, type
, mode
, value
);
343 public void elementDecl (String name
, String model
)
346 declFirst
.elementDecl (name
, model
);
347 declRest
.elementDecl (name
, model
);
350 public void externalEntityDecl (String name
,
351 String publicId
, String systemId
)
354 declFirst
.externalEntityDecl (name
, publicId
, systemId
);
355 declRest
.externalEntityDecl (name
, publicId
, systemId
);
358 public void internalEntityDecl (String name
, String value
)
361 declFirst
.internalEntityDecl (name
, value
);
362 declRest
.internalEntityDecl (name
, value
);
369 public void comment (char ch
[], int start
, int length
)
372 lexFirst
.comment (ch
, start
, length
);
373 lexRest
.comment (ch
, start
, length
);
376 public void startCDATA ()
379 lexFirst
.startCDATA ();
380 lexRest
.startCDATA ();
383 public void endCDATA ()
386 lexFirst
.endCDATA ();
390 public void startEntity (String name
)
393 lexFirst
.startEntity (name
);
394 lexRest
.startEntity (name
);
397 public void endEntity (String name
)
400 lexFirst
.endEntity (name
);
401 lexRest
.endEntity (name
);
404 public void startDTD (String name
, String publicId
, String systemId
)
407 lexFirst
.startDTD (name
, publicId
, systemId
);
408 lexRest
.startDTD (name
, publicId
, systemId
);
411 public void endDTD ()