eventfilter.java
来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· Java 代码 · 共 787 行 · 第 1/2 页
JAVA
787 行
/* * Copyright (C) 1999-2001 David Brownell * * This file is part of GNU JAXP, a library. * * GNU JAXP is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * GNU JAXP is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * As a special exception, if you link this library with other files to * produce an executable, this library does not by itself cause the * resulting executable to be covered by the GNU General Public License. * This exception does not however invalidate any other reasons why the * executable file might be covered by the GNU General Public License. */package gnu.xml.pipeline;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import org.xml.sax.*;import org.xml.sax.ext.*;import org.xml.sax.helpers.XMLFilterImpl;/** * A customizable event consumer, used to assemble various kinds of filters * using SAX handlers and an optional second consumer. It can be constructed * in two ways: <ul> * * <li> To serve as a passthrough, sending all events to a second consumer. * The second consumer may be identified through {@link #getNext}. * * <li> To serve as a dead end, with all handlers null; * {@link #getNext} returns null. * * </ul> * * <p> Additionally, SAX handlers may be assigned, which completely replace * the "upstream" view (through {@link EventConsumer}) of handlers, initially * null or the "next" consumer provided to the constructor. To make * it easier to build specialized filter classes, this class implements * all the standard SAX consumer handlers, and those implementations * delegate "downstream" to the consumer accessed by {@link #getNext}. * * <p> The simplest way to create a custom a filter class is to create a * subclass which overrides one or more handler interface methods. The * constructor for that subclass then registers itself as a handler for * those interfaces using a call such as <em>setContentHandler(this)</em>, * so the "upstream" view of event delivery is modified from the state * established in the base class constructor. That way, * the overridden methods intercept those event callbacks * as they go "downstream", and * all other event callbacks will pass events to any next consumer. * Overridden methods may invoke superclass methods (perhaps after modifying * parameters) if they wish to delegate such calls. Such subclasses * should use {@link #getErrorHandler} to report errors using the * common error reporting mechanism. * * <p> Another important technique is to construct a filter consisting * of only a few specific types of handler. For example, one could easily * prune out lexical events or various declarations by providing handlers * which don't pass those events downstream, or by providing null handlers. * * <hr /> * * <p> This may be viewed as the consumer oriented analogue of the SAX2 * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class. * Key differences include: <ul> * * <li> This fully separates consumer and producer roles: it * does not implement the producer side <em>XMLReader</em> or * <em>EntityResolver</em> interfaces, so it can only be used * in "push" mode (it has no <em>parse()</em> methods). * * <li> "Extension" handlers are fully supported, enabling a * richer set of application requirements. * And it implements {@link EventConsumer}, which groups related * consumer methods together, rather than leaving them separated. * * <li> The chaining which is visible is "downstream" to the next * consumer, not "upstream" to the preceding producer. * It supports "fan-in", where * a consumer can be fed by several producers. (For "fan-out", * see the {@link TeeConsumer} class.) * * <li> Event chaining is set up differently. It is intended to * work "upstream" from terminus towards producer, during filter * construction, as described above. * This is part of an early binding model: * events don't need to pass through stages which ignore them. * * <li> ErrorHandler support is separated, on the grounds that * pipeline stages need to share the same error handling policy. * For the same reason, error handler setup goes "downstream": * when error handlers get set, they are passed to subsequent * consumers. * * </ul> * * <p> The {@link #chainTo chainTo()} convenience routine supports chaining to * an XMLFilterImpl, in its role as a limited functionality event * consumer. Its event producer role ({@link XMLFilter}) is ignored. * * <hr /> * * <p> The {@link #bind bind()} routine may be used associate event pipelines * with any kind of {@link XMLReader} that will produce the events. * Such pipelines don't necessarily need to have any members which are * implemented using this class. That routine has some intelligence * which supports automatic changes to parser feature flags, letting * event piplines become largely independent of the particular feature * sets of parsers. * * @author David Brownell */public class EventFilter implements EventConsumer, ContentHandler, DTDHandler, LexicalHandler, DeclHandler{ // SAX handlers private ContentHandler docHandler, docNext; private DTDHandler dtdHandler, dtdNext; private LexicalHandler lexHandler, lexNext; private DeclHandler declHandler, declNext; // and ideally, one more for the stuff SAX2 doesn't show private Locator locator; private EventConsumer next; private ErrorHandler errHandler; /** SAX2 URI prefix for standard feature flags. */ public static final String FEATURE_URI = "http://xml.org/sax/features/"; /** SAX2 URI prefix for standard properties (mostly for handlers). */ public static final String PROPERTY_URI = "http://xml.org/sax/properties/"; /** SAX2 property identifier for {@link DeclHandler} events */ public static final String DECL_HANDLER = PROPERTY_URI + "declaration-handler"; /** SAX2 property identifier for {@link LexicalHandler} events */ public static final String LEXICAL_HANDLER = PROPERTY_URI + "lexical-handler"; // // These class objects will be null if the relevant class isn't linked. // Small configurations (pJava and some kinds of embedded systems) need // to facilitate smaller executables. So "instanceof" is undesirable // when bind() sees if it can remove some stages. // // SECURITY NOTE: assuming all these classes are part of the same sealed // package, there's no problem saving these in the instance of this class // that's associated with "this" class loader. But that wouldn't be true // for classes in another package. // private static boolean loaded; private static Class nsClass; private static Class validClass; private static Class wfClass; private static Class xincClass; static ClassLoader getClassLoader () { Method m = null; try { m = Thread.class.getMethod("getContextClassLoader", null); } catch (NoSuchMethodException e) { // Assume that we are running JDK 1.1, use the current ClassLoader return EventFilter.class.getClassLoader(); } try { return (ClassLoader) m.invoke(Thread.currentThread(), null); } catch (IllegalAccessException e) { // assert(false) throw new UnknownError(e.getMessage()); } catch (InvocationTargetException e) { // assert(e.getTargetException() instanceof SecurityException) throw new UnknownError(e.getMessage()); } } static Class loadClass (ClassLoader classLoader, String className) { try { if (classLoader == null) return Class.forName(className); else return classLoader.loadClass(className); } catch (Exception e) { return null; } } static private void loadClasses () { ClassLoader loader = getClassLoader (); nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter"); validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer"); wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter"); xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter"); loaded = true; } /** * Binds the standard SAX2 handlers from the specified consumer * pipeline to the specified producer. These handlers include the core * {@link ContentHandler} and {@link DTDHandler}, plus the extension * {@link DeclHandler} and {@link LexicalHandler}. Any additional * application-specific handlers need to be bound separately. * The {@link ErrorHandler} is handled differently: the producer's * error handler is passed through to the consumer pipeline. * The producer is told to include namespace prefix information if it * can, since many pipeline stages need that Infoset information to * work well. * * <p> At the head of the pipeline, certain standard event filters are * recognized and handled specially. This facilitates construction * of processing pipelines that work regardless of the capabilities * of the XMLReader implementation in use; for example, it permits * validating output of a {@link gnu.xml.util.DomParser}. <ul> * * <li> {@link NSFilter} will be removed if the producer can be * told not to discard namespace data, using the "namespace-prefixes" * feature flag. * * <li> {@link ValidationConsumer} will be removed if the producer * can be told to validate, using the "validation" feature flag. * * <li> {@link WellFormednessFilter} is always removed, on the * grounds that no XMLReader is permitted to producee malformed * event streams and this would just be processing overhead. * * <li> {@link XIncludeFilter} stops the special handling, except * that it's told about the "namespace-prefixes" feature of the * event producer so that the event stream is internally consistent. * * <li> The first consumer which is not one of those classes stops * such special handling. This means that if you want to force * one of those filters to be used, you could just precede it with * an instance of {@link EventFilter} configured as a pass-through. * You might need to do that if you are using an {@link NSFilter} * subclass to fix names found in attributes or character data. * * </ul> * * <p> Other than that, this method works with any kind of event consumer, * not just event filters. Note that in all cases, the standard handlers * are assigned; any previous handler assignments for the handler will * be overridden. * * @param producer will deliver events to the specified consumer * @param consumer pipeline supplying event handlers to be associated * with the producer (may not be null) */ public static void bind (XMLReader producer, EventConsumer consumer) { Class klass = null; boolean prefixes; if (!loaded) loadClasses (); // DOM building, printing, layered validation, and other // things don't work well when prefix info is discarded. // Include it by default, whenever possible. try { producer.setFeature (FEATURE_URI + "namespace-prefixes", true); prefixes = true; } catch (SAXException e) { prefixes = false; } // NOTE: This loop doesn't use "instanceof", since that // would prevent compiling/linking without those classes // being present. while (consumer != null) { klass = consumer.getClass (); // we might have already changed this problematic SAX2 default. if (nsClass != null && nsClass.isAssignableFrom (klass)) { if (!prefixes) break; consumer = ((EventFilter)consumer).getNext (); // the parser _might_ do DTD validation by default ... // if not, maybe we can change this setting. } else if (validClass != null && validClass.isAssignableFrom (klass)) { try { producer.setFeature (FEATURE_URI + "validation", true); consumer = ((ValidationConsumer)consumer).getNext (); } catch (SAXException e) { break; } // parsers are required not to have such bugs } else if (wfClass != null && wfClass.isAssignableFrom (klass)) { consumer = ((WellFormednessFilter)consumer).getNext (); // stop on the first pipeline stage we can't remove } else break; if (consumer == null) klass = null; } // the actual setting here doesn't matter as much // as that producer and consumer agree if (xincClass != null && klass != null && xincClass.isAssignableFrom (klass)) ((XIncludeFilter)consumer).setSavingPrefixes (prefixes); // Some SAX parsers can't handle null handlers -- bleech DefaultHandler2 h = new DefaultHandler2 (); if (consumer != null && consumer.getContentHandler () != null) producer.setContentHandler (consumer.getContentHandler ()); else producer.setContentHandler (h); if (consumer != null && consumer.getDTDHandler () != null) producer.setDTDHandler (consumer.getDTDHandler ()); else producer.setDTDHandler (h); try { Object dh; if (consumer != null) dh = consumer.getProperty (DECL_HANDLER); else dh = null; if (dh == null) dh = h; producer.setProperty (DECL_HANDLER, dh); } catch (Exception e) { /* ignore */ } try { Object lh; if (consumer != null) lh = consumer.getProperty (LEXICAL_HANDLER); else lh = null; if (lh == null) lh = h; producer.setProperty (LEXICAL_HANDLER, lh); } catch (Exception e) { /* ignore */ } // this binding goes the other way around if (producer.getErrorHandler () == null) producer.setErrorHandler (h); if (consumer != null) consumer.setErrorHandler (producer.getErrorHandler ()); } /** * Initializes all handlers to null. */ // constructor used by PipelineFactory public EventFilter () { } /** * Handlers that are not otherwise set will default to those from * the specified consumer, making it easy to pass events through. * If the consumer is null, all handlers are initialzed to null. */ // constructor used by PipelineFactory public EventFilter (EventConsumer consumer) { if (consumer == null) return; next = consumer;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?