📄 eventfilter.java
字号:
/* EventFilter.java -- Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.This file is part of GNU Classpath.GNU Classpath is free software; you can redistribute it and/or modifyit under the terms of the GNU General Public License as published bythe Free Software Foundation; either version 2, or (at your option)any later version.GNU Classpath is distributed in the hope that it will be useful, butWITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNUGeneral Public License for more details.You should have received a copy of the GNU General Public Licensealong with GNU Classpath; see the file COPYING. If not, write to theFree Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA02110-1301 USA.Linking this library statically or dynamically with other modules ismaking a combined work based on this library. Thus, the terms andconditions of the GNU General Public License cover the wholecombination.As a special exception, the copyright holders of this library give youpermission to link this library with independent modules to produce anexecutable, regardless of the license terms of these independentmodules, and to copy and distribute the resulting executable underterms of your choice, provided that you also meet, for each linkedindependent module, the terms and conditions of the license of thatmodule. An independent module is a module which is not derived fromor based on this library. If you modify this library, you may extendthis exception to your version of the library, but you are notobligated to do so. If you do not wish to do so, delete thisexception statement from your version. */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;import gnu.xml.aelfred2.ContentHandler2;/** * 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, ContentHandler2, 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 + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -