Merge from the pain train
[official-gcc.git] / libjava / gnu / xml / pipeline / TeeConsumer.java
blob922e79cf29f12bf8a4781454d8366199df8dff5f
1 /* TeeConsumer.java --
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)
9 any later version.
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
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
24 combination.
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;
50 /**
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;
83 /**
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 ();
96 first = car;
97 rest = cdr;
100 // Cache the handlers.
102 docFirst = first.getContentHandler ();
103 docRest = rest.getContentHandler ();
104 // DTD handler isn't cached (rarely needed)
106 try {
107 declFirst = null;
108 declFirst = (DeclHandler) first.getProperty (
109 EventFilter.DECL_HANDLER);
110 } catch (SAXException e) {}
111 try {
112 declRest = null;
113 declRest = (DeclHandler) rest.getProperty (
114 EventFilter.DECL_HANDLER);
115 } catch (SAXException e) {}
117 try {
118 lexFirst = null;
119 lexFirst = (LexicalHandler) first.getProperty (
120 EventFilter.LEXICAL_HANDLER);
121 } catch (SAXException e) {}
122 try {
123 lexRest = null;
124 lexRest = (LexicalHandler) rest.getProperty (
125 EventFilter.LEXICAL_HANDLER);
126 } catch (SAXException e) {}
129 /* FIXME
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)
140 throws IOException
142 this (PipelineFactory.createPipeline (first), rest);
146 /** Returns the first pipeline to get event calls. */
147 public EventConsumer getFirst ()
148 { return first; }
150 /** Returns the second pipeline to get event calls. */
151 public EventConsumer getRest ()
152 { return rest; }
154 /** Returns the content handler being used. */
155 final public ContentHandler getContentHandler ()
157 if (docRest == null)
158 return docFirst;
159 if (docFirst == null)
160 return docRest;
161 return this;
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 ();
172 return this;
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)
190 return firstProp;
191 if (firstProp == null)
192 return restProp;
195 // we've got work to do; handle two builtin cases.
197 if (EventFilter.DECL_HANDLER.equals (id))
198 return this;
199 if (EventFilter.LEXICAL_HANDLER.equals (id))
200 return this;
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
211 * this filter stage.
213 public void setErrorHandler (ErrorHandler handler)
215 first.setErrorHandler (handler);
216 rest.setErrorHandler (handler);
221 // ContentHandler
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 ()
231 throws SAXException
233 docFirst.startDocument ();
234 docRest.startDocument ();
237 public void endDocument ()
238 throws SAXException
240 try {
241 docFirst.endDocument ();
242 } finally {
243 docRest.endDocument ();
247 public void startPrefixMapping (String prefix, String uri)
248 throws SAXException
250 docFirst.startPrefixMapping (prefix, uri);
251 docRest.startPrefixMapping (prefix, uri);
254 public void endPrefixMapping (String prefix)
255 throws SAXException
257 docFirst.endPrefixMapping (prefix);
258 docRest.endPrefixMapping (prefix);
261 public void skippedEntity (String name)
262 throws SAXException
264 docFirst.skippedEntity (name);
265 docRest.skippedEntity (name);
268 public void startElement (String uri, String localName,
269 String qName, Attributes atts)
270 throws SAXException
272 docFirst.startElement (uri, localName, qName, atts);
273 docRest.startElement (uri, localName, qName, atts);
276 public void endElement (String uri, String localName, String qName)
277 throws SAXException
279 docFirst.endElement (uri, localName, qName);
280 docRest.endElement (uri, localName, qName);
283 public void processingInstruction (String target, String data)
284 throws SAXException
286 docFirst.processingInstruction (target, data);
287 docRest.processingInstruction (target, data);
290 public void characters (char ch [], int start, int length)
291 throws SAXException
293 docFirst.characters (ch, start, length);
294 docRest.characters (ch, start, length);
297 public void ignorableWhitespace (char ch [], int start, int length)
298 throws SAXException
300 docFirst.ignorableWhitespace (ch, start, length);
301 docRest.ignorableWhitespace (ch, start, length);
306 // DTDHandler
308 public void notationDecl (String name, String publicId, String systemId)
309 throws SAXException
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,
320 String notationName
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);
332 // DeclHandler
334 public void attributeDecl (String eName, String aName,
335 String type,
336 String mode, String value)
337 throws SAXException
339 declFirst.attributeDecl (eName, aName, type, mode, value);
340 declRest.attributeDecl (eName, aName, type, mode, value);
343 public void elementDecl (String name, String model)
344 throws SAXException
346 declFirst.elementDecl (name, model);
347 declRest.elementDecl (name, model);
350 public void externalEntityDecl (String name,
351 String publicId, String systemId)
352 throws SAXException
354 declFirst.externalEntityDecl (name, publicId, systemId);
355 declRest.externalEntityDecl (name, publicId, systemId);
358 public void internalEntityDecl (String name, String value)
359 throws SAXException
361 declFirst.internalEntityDecl (name, value);
362 declRest.internalEntityDecl (name, value);
367 // LexicalHandler
369 public void comment (char ch [], int start, int length)
370 throws SAXException
372 lexFirst.comment (ch, start, length);
373 lexRest.comment (ch, start, length);
376 public void startCDATA ()
377 throws SAXException
379 lexFirst.startCDATA ();
380 lexRest.startCDATA ();
383 public void endCDATA ()
384 throws SAXException
386 lexFirst.endCDATA ();
387 lexRest.endCDATA ();
390 public void startEntity (String name)
391 throws SAXException
393 lexFirst.startEntity (name);
394 lexRest.startEntity (name);
397 public void endEntity (String name)
398 throws SAXException
400 lexFirst.endEntity (name);
401 lexRest.endEntity (name);
404 public void startDTD (String name, String publicId, String systemId)
405 throws SAXException
407 lexFirst.startDTD (name, publicId, systemId);
408 lexRest.startDTD (name, publicId, systemId);
411 public void endDTD ()
412 throws SAXException
414 lexFirst.endDTD ();
415 lexRest.endDTD ();