mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			724 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			724 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
/* PipelineFactory.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 modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the 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, 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 GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package gnu.xml.pipeline;
 | 
						|
 | 
						|
import java.io.File;
 | 
						|
import java.io.FileOutputStream;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.OutputStream;
 | 
						|
import java.io.OutputStreamWriter;
 | 
						|
import java.lang.reflect.Constructor;
 | 
						|
import java.util.StringTokenizer;
 | 
						|
 | 
						|
import org.xml.sax.*;
 | 
						|
import org.xml.sax.ext.*;
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
 * This provides static factory methods for creating simple event pipelines.
 | 
						|
 * These pipelines are specified by strings, suitable for passing on
 | 
						|
 * command lines or embedding in element attributes.  For example, one way
 | 
						|
 * to write a pipeline that restores namespace syntax, validates (stopping
 | 
						|
 * the pipeline on validity errors) and then writes valid data to standard
 | 
						|
 * output is this: <pre>
 | 
						|
 *      nsfix | validate | write ( stdout )</pre>
 | 
						|
 *
 | 
						|
 * <p> In this syntax, the tokens are always separated by whitespace, and each
 | 
						|
 * stage of the pipeline may optionally have a parameter (which can be a
 | 
						|
 * pipeline) in parentheses.  Interior stages are called filters, and the
 | 
						|
 * rightmost end of a pipeline is called a terminus.
 | 
						|
 *
 | 
						|
 * <p> Stages are usually implemented by a single class, which may not be
 | 
						|
 * able to act as both a filter and a terminus; but any terminus can be
 | 
						|
 * automatically turned into a filter, through use of a {@link TeeConsumer}.
 | 
						|
 * The stage identifiers are either class names, or are one of the following
 | 
						|
 * short identifiers built into this class.  (Most of these identifiers are
 | 
						|
 * no more than aliases for classes.)  The built-in identifiers include:</p>
 | 
						|
 
 | 
						|
 <table border="1" cellpadding="3" cellspacing="0">
 | 
						|
    <tr bgcolor="#ccccff" class="TableHeadingColor">
 | 
						|
	<th align="center" width="5%">Stage</th>
 | 
						|
	<th align="center" width="9%">Parameter</th>
 | 
						|
	<th align="center" width="1%">Terminus</th>
 | 
						|
	<th align="center">Description</th>
 | 
						|
    </tr>
 | 
						|
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="../dom/Consumer.html">dom</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td> yes </td>
 | 
						|
	<td align="left"> Applications code can access a DOM Document built
 | 
						|
	from the input event stream.  When used as a filter, this buffers
 | 
						|
	data up to an <em>endDocument</em> call, and then uses a DOM parser
 | 
						|
	to report everything that has been recorded (which can easily be
 | 
						|
	less than what was reported to it).  </td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="NSFilter.html">nsfix</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td>no</td>
 | 
						|
	<td align="left">This stage ensures that the XML element and attribute
 | 
						|
	names in its output use namespace prefixes and declarations correctly.
 | 
						|
	That is, so that they match the "Namespace plus LocalName" naming data
 | 
						|
	with which each XML element and attribute is already associated.  </td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="EventFilter.html">null</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td>yes</td>
 | 
						|
	<td align="left">This stage ignores all input event data.</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="CallFilter.html">server</a></td>
 | 
						|
	<td><em>required</em><br> server URL </td>
 | 
						|
	<td>no</td>
 | 
						|
	<td align="left">Sends its input as XML request to a remote server,
 | 
						|
	normally a web application server using the HTTP or HTTPS protocols.
 | 
						|
	The output of this stage is the parsed response from that server.</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="TeeConsumer.html">tee</a></td>
 | 
						|
	<td><em>required</em><br> first pipeline</td>
 | 
						|
	<td>no</td>
 | 
						|
	<td align="left">This sends its events down two paths; its parameter
 | 
						|
	is a pipeline descriptor for the first path, and the second path
 | 
						|
	is the output of this stage.</td>
 | 
						|
    </tr>
 | 
						|
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="ValidationConsumer.html">validate</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td>yes</td>
 | 
						|
	<td align="left">This checks for validity errors, and reports them
 | 
						|
	through its error handler.  The input must include declaration events
 | 
						|
	and some lexical events.  </td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="WellFormednessFilter.html">wf</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td>yes</td>
 | 
						|
	<td align="left"> This class provides some basic "well formedness"
 | 
						|
	tests on the input event stream, and reports a fatal error if any
 | 
						|
	of them fail.  One example: start/end calls for elements must match.
 | 
						|
	No SAX parser is permitted to produce malformed output, but other
 | 
						|
	components can easily do so.</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td>write</td>
 | 
						|
	<td><em>required</em><br> "stdout", "stderr", or filename</td>
 | 
						|
	<td>yes</td>
 | 
						|
	<td align="left"> Writes its input to the specified output, as pretty
 | 
						|
	printed XML text encoded using UTF-8.  Input events must be well
 | 
						|
	formed and "namespace fixed", else the output won't be XML (or possibly
 | 
						|
	namespace) conformant.  The symbolic names represent
 | 
						|
	<em>System.out</em> and <em>System.err</em> respectively; names must
 | 
						|
	correspond to files which don't yet exist.</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td>xhtml</td>
 | 
						|
	<td><em>required</em><br> "stdout", "stderr", or filename</td>
 | 
						|
	<td>yes</td>
 | 
						|
	<td align="left"> Like <em>write</em> (above), except that XHTML rules
 | 
						|
	are followed.  The XHTML 1.0 Transitional document type is declared,
 | 
						|
	and only ASCII characters are written (for interoperability).  Other
 | 
						|
	characters are written as entity or character references; the text is
 | 
						|
	pretty printed.</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="XIncludeFilter.html">xinclude</a></td>
 | 
						|
	<td><em>none</em></td>
 | 
						|
	<td>no</td>
 | 
						|
	<td align="left">This stage handles XInclude processing.
 | 
						|
	This is like entity inclusion, except that the included content
 | 
						|
	is declared in-line rather than in the DTD at the beginning of
 | 
						|
	a document.
 | 
						|
	</td>
 | 
						|
    </tr>
 | 
						|
    <tr valign="top" align="center">
 | 
						|
	<td><a href="XsltFilter.html">xslt</a></td>
 | 
						|
	<td><em>required</em><br> XSLT stylesheet URI</td>
 | 
						|
	<td>no</td>
 | 
						|
	<td align="left">This stage handles XSLT transformation
 | 
						|
	according to a stylesheet.
 | 
						|
	The implementation of the transformation may not actually
 | 
						|
	stream data, although if such an XSLT engine is in use
 | 
						|
	then that can happen.
 | 
						|
	</td>
 | 
						|
    </tr>
 | 
						|
 | 
						|
 </table>
 | 
						|
 
 | 
						|
 * <p> Note that {@link EventFilter#bind} can automatically eliminate
 | 
						|
 * some filters by setting SAX2 parser features appropriately.  This means
 | 
						|
 * that you can routinely put filters like "nsfix", "validate", or "wf" at the
 | 
						|
 * front of a pipeline (for components that need inputs conditioned to match
 | 
						|
 * that level of correctness), and know that it won't actually be used unless
 | 
						|
 * it's absolutely necessary.
 | 
						|
 *
 | 
						|
 * @author David Brownell
 | 
						|
 */
 | 
						|
public class PipelineFactory
 | 
						|
{
 | 
						|
    /**
 | 
						|
     * Creates a simple pipeline according to the description string passed in.
 | 
						|
     */
 | 
						|
    public static EventConsumer createPipeline (String description)
 | 
						|
    throws IOException
 | 
						|
    {
 | 
						|
	return createPipeline (description, null);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Extends an existing pipeline by prepending the filter pipeline to the
 | 
						|
     * specified consumer.  Some pipelines need more customization than can
 | 
						|
     * be done through this simplified syntax.  When they are set up with
 | 
						|
     * direct API calls, use this method to merge more complex pipeline
 | 
						|
     * segments with easily configured ones.
 | 
						|
     */
 | 
						|
    public static EventConsumer createPipeline (
 | 
						|
	String		description,
 | 
						|
	EventConsumer	next
 | 
						|
    ) throws IOException
 | 
						|
    {
 | 
						|
	// tokens are (for now) what's separated by whitespace;
 | 
						|
	// very easy to parse, but IDs never have spaces.
 | 
						|
 | 
						|
	StringTokenizer		tokenizer;
 | 
						|
	String			tokens [];
 | 
						|
 | 
						|
	tokenizer = new StringTokenizer (description);
 | 
						|
	tokens = new String [tokenizer.countTokens ()];
 | 
						|
	for (int i = 0; i < tokens.length; i++)
 | 
						|
	    tokens [i] = tokenizer.nextToken ();
 | 
						|
 | 
						|
	PipelineFactory		factory = new PipelineFactory ();
 | 
						|
	Pipeline		pipeline = factory.parsePipeline (tokens, next);
 | 
						|
 | 
						|
	return pipeline.createPipeline ();
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    private PipelineFactory () { /* NYET */ }
 | 
						|
 | 
						|
 | 
						|
    /**
 | 
						|
     * Extends an existing pipeline by prepending a pre-tokenized filter
 | 
						|
     * pipeline to the specified consumer.  Tokens are class names (or the
 | 
						|
     * predefined aliases) left and right parenthesis, and the vertical bar.
 | 
						|
     */
 | 
						|
    public static EventConsumer createPipeline (
 | 
						|
	String		tokens [],
 | 
						|
	EventConsumer	next
 | 
						|
    ) throws IOException
 | 
						|
    {
 | 
						|
	PipelineFactory		factory = new PipelineFactory ();
 | 
						|
	Pipeline		pipeline = factory.parsePipeline (tokens, next);
 | 
						|
 | 
						|
	return pipeline.createPipeline ();
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    private String		tokens [];
 | 
						|
    private int			index;
 | 
						|
 | 
						|
    private Pipeline parsePipeline (String toks [], EventConsumer next)
 | 
						|
    {
 | 
						|
	tokens = toks;
 | 
						|
	index = 0;
 | 
						|
	
 | 
						|
	Pipeline retval = parsePipeline (next);
 | 
						|
 | 
						|
	if (index != toks.length)
 | 
						|
	    throw new ArrayIndexOutOfBoundsException (
 | 
						|
		    "extra token: " + tokens [index]);
 | 
						|
	return retval;
 | 
						|
    }
 | 
						|
 | 
						|
    // pipeline  ::= stage | stage '|' pipeline
 | 
						|
    private Pipeline parsePipeline (EventConsumer next)
 | 
						|
    {
 | 
						|
	Pipeline	retval = new Pipeline (parseStage ());
 | 
						|
 | 
						|
	// minimal pipelines:  "stage" and "... | id"
 | 
						|
	if (index > (tokens.length - 2)
 | 
						|
		|| !"|".equals (tokens [index])
 | 
						|
		) {
 | 
						|
	    retval.next = next;
 | 
						|
	    return retval;
 | 
						|
	}
 | 
						|
	index++;
 | 
						|
	retval.rest = parsePipeline (next);
 | 
						|
	return retval;
 | 
						|
    }
 | 
						|
 | 
						|
    // stage     ::= id    | id '(' pipeline ')'
 | 
						|
    private Stage parseStage ()
 | 
						|
    {
 | 
						|
	Stage		retval = new Stage (tokens [index++]);
 | 
						|
 | 
						|
	// minimal stages:  "id" and "id ( id )"
 | 
						|
	if (index > (tokens.length - 2)
 | 
						|
		|| !"(".equals (tokens [index]) /*)*/
 | 
						|
		)
 | 
						|
	    return retval;
 | 
						|
	
 | 
						|
	index++;
 | 
						|
	retval.param = parsePipeline (null);
 | 
						|
	if (index >= tokens.length)
 | 
						|
	    throw new ArrayIndexOutOfBoundsException (
 | 
						|
		    "missing right paren");
 | 
						|
	if (/*(*/ !")".equals (tokens [index++]))
 | 
						|
	    throw new ArrayIndexOutOfBoundsException (
 | 
						|
		    "required right paren, not: " + tokens [index - 1]);
 | 
						|
	return retval;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    //
 | 
						|
    // these classes obey the conventions for constructors, so they're
 | 
						|
    // only built in to this table of shortnames
 | 
						|
    //
 | 
						|
    //	- filter (one or two types of arglist)
 | 
						|
    //	   * last constructor is 'next' element
 | 
						|
    //	   * optional (first) string parameter
 | 
						|
    //
 | 
						|
    //	- terminus (one or types of arglist)
 | 
						|
    //	   * optional (only) string parameter
 | 
						|
    //
 | 
						|
    // terminus stages are transformed into filters if needed, by
 | 
						|
    // creating a "tee".  filter stages aren't turned to terminus
 | 
						|
    // stages though; either eliminate such stages, or add some
 | 
						|
    // terminus explicitly.
 | 
						|
    //
 | 
						|
    private static final String builtinStages [][] = {
 | 
						|
	{ "dom",	"gnu.xml.dom.Consumer" },
 | 
						|
	{ "nsfix",	"gnu.xml.pipeline.NSFilter" },
 | 
						|
	{ "null",	"gnu.xml.pipeline.EventFilter" },
 | 
						|
	{ "server",	"gnu.xml.pipeline.CallFilter" },
 | 
						|
	{ "tee",	"gnu.xml.pipeline.TeeConsumer" },
 | 
						|
	{ "validate",	"gnu.xml.pipeline.ValidationConsumer" },
 | 
						|
	{ "wf",		"gnu.xml.pipeline.WellFormednessFilter" },
 | 
						|
	{ "xinclude",	"gnu.xml.pipeline.XIncludeFilter" },
 | 
						|
	{ "xslt",	"gnu.xml.pipeline.XsltFilter" },
 | 
						|
 | 
						|
// XXX want:  option for validate, to preload external part of a DTD
 | 
						|
 | 
						|
	    //	xhtml, write ... nyet generic-ready
 | 
						|
    };
 | 
						|
 | 
						|
    private static class Stage
 | 
						|
    {
 | 
						|
	String		id;
 | 
						|
	Pipeline	param;
 | 
						|
 | 
						|
	Stage (String name)
 | 
						|
	    {  id = name; }
 | 
						|
 | 
						|
	public String toString ()
 | 
						|
	{
 | 
						|
	    if (param == null)
 | 
						|
		return id;
 | 
						|
	    return id + " ( " + param + " )";
 | 
						|
	}
 | 
						|
 | 
						|
	private void fail (String message)
 | 
						|
	throws IOException
 | 
						|
	{
 | 
						|
	    throw new IOException ("in '" + id
 | 
						|
		    + "' stage of pipeline, " + message);
 | 
						|
	}
 | 
						|
 | 
						|
	EventConsumer createStage (EventConsumer next)
 | 
						|
	throws IOException
 | 
						|
	{
 | 
						|
	    String	 name = id;
 | 
						|
 | 
						|
	    // most builtins are just class aliases
 | 
						|
	    for (int i = 0; i < builtinStages.length; i++) {
 | 
						|
		if (id.equals (builtinStages [i][0])) {
 | 
						|
		    name = builtinStages [i][1];
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
 | 
						|
	    // Save output as XML or XHTML text
 | 
						|
	    if ("write".equals (name) || "xhtml".equals (name)) {
 | 
						|
		String		filename;
 | 
						|
		boolean		isXhtml = "xhtml".equals (name);
 | 
						|
		OutputStream	out = null;
 | 
						|
		TextConsumer	consumer;
 | 
						|
 | 
						|
		if (param == null)
 | 
						|
		    fail ("parameter is required");
 | 
						|
 | 
						|
		filename = param.toString ();
 | 
						|
		if ("stdout".equals (filename))
 | 
						|
		    out = System.out;
 | 
						|
		else if ("stderr".equals (filename))
 | 
						|
		    out = System.err;
 | 
						|
		else {
 | 
						|
		    File f = new File (filename);
 | 
						|
 | 
						|
/*
 | 
						|
		    if (!f.isAbsolute ())
 | 
						|
			fail ("require absolute file paths");
 | 
						|
 */
 | 
						|
		    if (f.exists ())
 | 
						|
			fail ("file already exists: " + f.getName ());
 | 
						|
 | 
						|
// XXX this races against the existence test
 | 
						|
		    out = new FileOutputStream (f);
 | 
						|
		}
 | 
						|
		
 | 
						|
		if (!isXhtml)
 | 
						|
		    consumer = new TextConsumer (out);
 | 
						|
		else
 | 
						|
		    consumer = new TextConsumer (
 | 
						|
			new OutputStreamWriter (out, "8859_1"),
 | 
						|
			true);
 | 
						|
		
 | 
						|
		consumer.setPrettyPrinting (true);
 | 
						|
		if (next == null)
 | 
						|
		    return consumer;
 | 
						|
		return new TeeConsumer (consumer, next);
 | 
						|
 | 
						|
	    } else {
 | 
						|
		//
 | 
						|
		// Here go all the builtins that are just aliases for
 | 
						|
		// classes, and all stage IDs that started out as such
 | 
						|
		// class names.  The following logic relies on several
 | 
						|
		// documented conventions for constructor invocation.
 | 
						|
		//
 | 
						|
		String		msg = null;
 | 
						|
 | 
						|
		try {
 | 
						|
		    Class	klass = Class.forName (name);
 | 
						|
		    Class	argTypes [] = null;
 | 
						|
		    Constructor	constructor = null;
 | 
						|
		    boolean	filter = false;
 | 
						|
		    Object	params [] = null;
 | 
						|
		    Object	obj = null;
 | 
						|
 | 
						|
		    // do we need a filter stage?
 | 
						|
		    if (next != null) {
 | 
						|
			// "next" consumer is always passed, with
 | 
						|
			// or without the optional string param
 | 
						|
			if (param == null) {
 | 
						|
			    argTypes = new Class [1];
 | 
						|
			    argTypes [0] = EventConsumer.class;
 | 
						|
 | 
						|
			    params = new Object [1];
 | 
						|
			    params [0] = next;
 | 
						|
 | 
						|
			    msg = "no-param filter";
 | 
						|
			} else {
 | 
						|
			    argTypes = new Class [2];
 | 
						|
			    argTypes [0] = String.class;
 | 
						|
			    argTypes [1] = EventConsumer.class;
 | 
						|
 | 
						|
			    params = new Object [2];
 | 
						|
			    params [0] = param.toString ();
 | 
						|
			    params [1] = next;
 | 
						|
 | 
						|
			    msg = "one-param filter";
 | 
						|
			}
 | 
						|
 | 
						|
 | 
						|
			try {
 | 
						|
			    constructor = klass.getConstructor (argTypes);
 | 
						|
			} catch (NoSuchMethodException e) {
 | 
						|
			    // try creating a filter from a
 | 
						|
			    // terminus and a tee
 | 
						|
			    filter = true;
 | 
						|
			    msg += " built from ";
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		    // build from a terminus stage, with or
 | 
						|
		    // without the optional string param
 | 
						|
		    if (constructor == null) {
 | 
						|
			String	tmp;
 | 
						|
 | 
						|
			if (param == null) {
 | 
						|
			    argTypes = new Class [0];
 | 
						|
			    params = new Object [0];
 | 
						|
 | 
						|
			    tmp = "no-param terminus";
 | 
						|
			} else {
 | 
						|
			    argTypes = new Class [1];
 | 
						|
			    argTypes [0] = String.class;
 | 
						|
 | 
						|
			    params = new Object [1];
 | 
						|
			    params [0] = param.toString ();
 | 
						|
 | 
						|
			    tmp = "one-param terminus";
 | 
						|
			}
 | 
						|
			if (msg == null)
 | 
						|
			    msg = tmp;
 | 
						|
			else
 | 
						|
			    msg += tmp;
 | 
						|
			constructor = klass.getConstructor (argTypes);
 | 
						|
			    // NOT creating terminus by dead-ending
 | 
						|
			    // filters ... users should think about
 | 
						|
			    // that one, something's likely wrong
 | 
						|
		    }
 | 
						|
		    
 | 
						|
		    obj = constructor.newInstance (params);
 | 
						|
 | 
						|
		    // return EventConsumers directly, perhaps after
 | 
						|
		    // turning them into a filter
 | 
						|
		    if (obj instanceof EventConsumer) {
 | 
						|
			if (filter)
 | 
						|
			    return new TeeConsumer ((EventConsumer) obj, next);
 | 
						|
			return (EventConsumer) obj;
 | 
						|
		    }
 | 
						|
		    
 | 
						|
		    // if it's not a handler, it's an error
 | 
						|
		    // we can wrap handlers in a filter
 | 
						|
		    EventFilter		retval = new EventFilter ();
 | 
						|
		    boolean		updated = false;
 | 
						|
 | 
						|
		    if (obj instanceof ContentHandler) {
 | 
						|
			retval.setContentHandler ((ContentHandler) obj);
 | 
						|
			updated = true;
 | 
						|
		    }
 | 
						|
		    if (obj instanceof DTDHandler) {
 | 
						|
			retval.setDTDHandler ((DTDHandler) obj);
 | 
						|
			updated = true;
 | 
						|
		    }
 | 
						|
		    if (obj instanceof LexicalHandler) {
 | 
						|
			retval.setProperty (
 | 
						|
			    EventFilter.PROPERTY_URI + "lexical-handler",
 | 
						|
			    obj);
 | 
						|
			updated = true;
 | 
						|
		    }
 | 
						|
		    if (obj instanceof DeclHandler) {
 | 
						|
			retval.setProperty (
 | 
						|
			    EventFilter.PROPERTY_URI + "declaration-handler",
 | 
						|
			    obj);
 | 
						|
			updated = true;
 | 
						|
		    }
 | 
						|
 | 
						|
		    if (!updated)
 | 
						|
			fail ("class is neither Consumer nor Handler");
 | 
						|
		    
 | 
						|
		    if (filter)
 | 
						|
			return new TeeConsumer (retval, next);
 | 
						|
		    return retval;
 | 
						|
 | 
						|
		} catch (IOException e) {
 | 
						|
		    throw e;
 | 
						|
 | 
						|
		} catch (NoSuchMethodException e) {
 | 
						|
		    fail (name + " constructor missing -- " + msg);
 | 
						|
 | 
						|
		} catch (ClassNotFoundException e) {
 | 
						|
		    fail (name + " class not found");
 | 
						|
 | 
						|
		} catch (Exception e) {
 | 
						|
		    // e.printStackTrace ();
 | 
						|
		    fail ("stage not available: " + e.getMessage ());
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	    // NOTREACHED
 | 
						|
	    return null;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
    private static class Pipeline
 | 
						|
    {
 | 
						|
	Stage		stage;
 | 
						|
 | 
						|
	// rest may be null
 | 
						|
	Pipeline	rest;
 | 
						|
	EventConsumer	next;
 | 
						|
 | 
						|
	Pipeline (Stage s)
 | 
						|
	    { stage = s; }
 | 
						|
 | 
						|
	public String toString ()
 | 
						|
	{
 | 
						|
	    if (rest == null && next == null)
 | 
						|
		return stage.toString ();
 | 
						|
	    if (rest != null)
 | 
						|
		return stage + " | " + rest;
 | 
						|
	    throw new IllegalArgumentException ("next");
 | 
						|
	}
 | 
						|
 | 
						|
	EventConsumer createPipeline ()
 | 
						|
	throws IOException
 | 
						|
	{
 | 
						|
	    if (next == null) {
 | 
						|
		if (rest == null)
 | 
						|
		    next = stage.createStage (null);
 | 
						|
		else
 | 
						|
		    next = stage.createStage (rest.createPipeline ());
 | 
						|
	    }
 | 
						|
	    return next;
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
/*
 | 
						|
    public static void main (String argv [])
 | 
						|
    {
 | 
						|
	try {
 | 
						|
	    // three basic terminus cases
 | 
						|
	    createPipeline ("null");
 | 
						|
	    createPipeline ("validate");
 | 
						|
	    createPipeline ("write ( stdout )");
 | 
						|
 | 
						|
	    // four basic filters
 | 
						|
	    createPipeline ("nsfix | write ( stderr )");
 | 
						|
	    createPipeline ("wf | null");
 | 
						|
	    createPipeline ("null | null");
 | 
						|
	    createPipeline (
 | 
						|
"call ( http://www.example.com/services/xml-1a ) | xhtml ( stdout )");
 | 
						|
 | 
						|
	    // tee junctions
 | 
						|
	    createPipeline ("tee ( validate ) | write ( stdout )");
 | 
						|
	    createPipeline ("tee ( nsfix | write ( stdout ) ) | validate");
 | 
						|
 | 
						|
	    // longer pipeline
 | 
						|
	    createPipeline ("nsfix | tee ( validate ) | write ( stdout )");
 | 
						|
	    createPipeline (
 | 
						|
		"null | wf | nsfix | tee ( validate ) | write ( stdout )");
 | 
						|
 | 
						|
	    // try some parsing error cases
 | 
						|
	    try {
 | 
						|
		createPipeline ("null (");		// extra token '('
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	    try {
 | 
						|
		createPipeline ("nsfix |");		// extra token '|'
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	    try {
 | 
						|
		createPipeline ("xhtml ( foo");		// missing right paren
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	    try {
 | 
						|
		createPipeline ("xhtml ( foo bar");	// required right paren
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	    try {
 | 
						|
		createPipeline ("tee ( nsfix | validate");// missing right paren
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	    // try some construction error cases
 | 
						|
 | 
						|
	    try {
 | 
						|
		createPipeline ("call");		// missing param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("call ( foobar )");	// broken param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("nsfix ( foobar )");	// illegal param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("null ( foobar )");	// illegal param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("wf ( foobar )");	// illegal param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("xhtml ( foobar.html )");
 | 
						|
		new File ("foobar.html").delete ();
 | 
						|
		// now supported
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("** err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("xhtml");		// missing param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("write ( stdout ) | null");	// nonterminal
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("validate | null");
 | 
						|
		// now supported
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("** err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("validate ( foo )");	// illegal param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		createPipeline ("tee");			// missing param
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
	    try {
 | 
						|
		    // only builtins so far
 | 
						|
		createPipeline ("com.example.xml.FilterClass");
 | 
						|
		System.err.println ("** didn't report error");
 | 
						|
	    } catch (Exception e) {
 | 
						|
		System.err.println ("== err: " + e.getMessage ()); }
 | 
						|
 | 
						|
	} catch (Exception e) {
 | 
						|
	    e.printStackTrace ();
 | 
						|
	}
 | 
						|
    }
 | 
						|
/**/
 | 
						|
 | 
						|
}
 |