diff options
Diffstat (limited to 'libjava/classpath/gnu/xml/pipeline/CallFilter.java')
-rw-r--r-- | libjava/classpath/gnu/xml/pipeline/CallFilter.java | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/xml/pipeline/CallFilter.java b/libjava/classpath/gnu/xml/pipeline/CallFilter.java new file mode 100644 index 000000000..2398b8685 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/CallFilter.java @@ -0,0 +1,257 @@ +/* CallFilter.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.IOException; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.net.URLConnection; +import java.io.Writer; + +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import gnu.xml.util.Resolver; +import gnu.xml.util.XMLWriter; + + +/** + * Input is sent as an XML request to given URI, and the output of this + * filter is the parsed response to that request. + * A connection is opened to the remote URI when the startDocument call is + * issued through this filter, and the request is finished when the + * endDocument call is issued. Events should be written quickly enough to + * prevent the remote HTTP server from aborting the connection due to + * inactivity; you may want to buffer text in an earlier pipeline stage. + * If your application requires validity checking of such + * outputs, have the output pipeline include a validation stage. + * + * <p>In effect, this makes a remote procedure call to the URI, with the + * request and response document syntax as chosen by the application. + * <em>Note that all the input events must be seen, and sent to the URI, + * before the first output event can be seen. </em> Clients are delayed + * at least by waiting for the server to respond, constraining concurrency. + * Services can thus be used to synchronize concurrent activities, and + * even to prioritize service among different clients. + * + * <p> You are advised to avoid restricting yourself to an "RPC" model + * for distributed computation. With a World Wide Web, network latencies + * and failures (e.g. non-availability) + * are significant; adopting a "procedure" model, rather than a workflow + * model where bulk requests are sent and worked on asynchronously, is not + * generally an optimal system-wide architecture. When the messages may + * need authentication, such as with an OpenPGP signature, or when server + * loads don't argue in favor of immediate responses, non-RPC models can + * be advantageous. (So-called "peer to peer" computing models are one + * additional type of model, though too often that term is applied to + * systems that still have a centralized control structure.) + * + * <p> <em>Be strict in what you send, liberal in what you accept,</em> as + * the Internet tradition goes. Strictly conformant data should never cause + * problems to its receiver; make your request pipeline be very strict, and + * don't compromise on that. Make your response pipeline strict as well, + * but be ready to tolerate specific mild, temporary, and well-documented + * variations from specific communications peers. + * + * @see XmlServlet + * + * @author David Brownell + */ +final public class CallFilter implements EventConsumer +{ + private Requestor req; + private EventConsumer next; + private URL target; + private URLConnection conn; + private ErrorHandler errHandler; + + + /** + * Initializes a call filter so that its inputs are sent to the + * specified URI, and its outputs are sent to the next consumer + * provided. + * + * @exception IOException if the URI isn't accepted as a URL + */ + // constructor used by PipelineFactory + public CallFilter (String uri, EventConsumer next) + throws IOException + { + this.next = next; + req = new Requestor (); + setCallTarget (uri); + } + + /** + * Assigns the URI of the call target to be used. + * Does not affect calls currently being made. + */ + final public void setCallTarget (String uri) + throws IOException + { + target = new URL (uri); + } + + /** + * Assigns the error handler to be used to present most fatal + * errors. + */ + public void setErrorHandler (ErrorHandler handler) + { + req.setErrorHandler (handler); + } + + + /** + * Returns the call target's URI. + */ + final public String getCallTarget () + { + return target.toString (); + } + + /** Returns the content handler currently in use. */ + final public org.xml.sax.ContentHandler getContentHandler () + { + return req; + } + + /** Returns the DTD handler currently in use. */ + final public DTDHandler getDTDHandler () + { + return req; + } + + + /** + * Returns the declaration or lexical handler currently in + * use, or throws an exception for other properties. + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (EventFilter.DECL_HANDLER.equals (id)) + return req; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return req; + throw new SAXNotRecognizedException (id); + } + + + // JDK 1.1 seems to need it to be done this way, sigh + ErrorHandler getErrorHandler () { return errHandler; } + + // + // Takes input and echoes to server as POST input. + // Then sends the POST reply to the next pipeline element. + // + final class Requestor extends XMLWriter + { + Requestor () + { + super ((Writer)null); + } + + public synchronized void startDocument () throws SAXException + { + // Connect to remote object and set up to send it XML text + try { + if (conn != null) + throw new IllegalStateException ("call is being made"); + + conn = target.openConnection (); + conn.setDoOutput (true); + conn.setRequestProperty ("Content-Type", + "application/xml;charset=UTF-8"); + + setWriter (new OutputStreamWriter ( + conn.getOutputStream (), + "UTF8"), "UTF-8"); + + } catch (IOException e) { + fatal ("can't write (POST) to URI: " + target, e); + } + + // NOW base class can safely write that text! + super.startDocument (); + } + + public void endDocument () throws SAXException + { + // + // Finish writing the request (for HTTP, a POST); + // this closes the output stream. + // + super.endDocument (); + + // + // Receive the response. + // Produce events for the next stage. + // + InputSource source; + XMLReader producer; + String encoding; + + try { + + source = new InputSource (conn.getInputStream ()); + +// FIXME if status is anything but success, report it!! It'd be good to +// save the request data just in case we need to deal with a forward. + + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding != null) + source.setEncoding (encoding); + + producer = XMLReaderFactory.createXMLReader (); + producer.setErrorHandler (getErrorHandler ()); + EventFilter.bind (producer, next); + producer.parse (source); + conn = null; + + } catch (IOException e) { + fatal ("I/O Exception reading response, " + e.getMessage (), e); + } + } + } +} |