Package org.apache.cocoon.generation

Source Code of org.apache.cocoon.generation.HttpProxyGenerator

/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.generation;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.avalon.framework.service.ServiceException;

import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.environment.SourceResolver;

import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;

import org.apache.excalibur.xml.sax.SAXParser;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
* The <code>HttpProxyGenerator</code> is a Cocoon generator using the
* <b>Jakarta Commons HTTPClient Library</b> to access an XML stream
* over HTTP.
*
* @author <a href="mailto:ivelin@apache.org">Ivelin Ivanov</a>, June 2002
* @author <a href="mailto:tony@apache.org">Tony Collen</a>, December 2002
* @author <a href="mailto:pier@apache.org">Pier Fumagalli</a>, February 2003
* @version CVS $Id: HttpProxyGenerator.java,v 1.7 2004/03/05 13:02:20 bdelacretaz Exp $
*/
public class HttpProxyGenerator extends ServiceableGenerator implements Configurable {

    /** The HTTP method to use at request time. */
    private HttpMethodBase method = null;
    /** The base HTTP URL for requests. */
    private HttpURL url = null;
    /** The list of request parameters for the request */
    private ArrayList reqParams = null;
    /** The list of query parameters for the request */
    private ArrayList qryParams = null;
    /** Wether we want a debug output or not */
    private boolean debug = false;

    /**
     * Default (empty) constructor.
     */
    public HttpProxyGenerator() {
        super();
    }

    /**
     * Set up this <code>Generator</code> instance from its sitemap <code>Configuration</code>
     *
     * @param configuration The base <code>Configuration</code> for this <code>Generator</code>.
     * @throws ConfigurationException If this instance cannot be configured properly.
     * @see #recycle()
     */
    public void configure(Configuration configuration)
    throws ConfigurationException {

        /* Setup the HTTP method to use. */
        String method = configuration.getChild("method").getValue("GET");
        if ("GET".equalsIgnoreCase(method)) {
            this.method = new GetMethod();
        } else if ("POST".equalsIgnoreCase(method)) {
            this.method = new PostMethod();
            /* TODO: Is this still needed? Does it refer to a bug in bugzilla?
             *       At least the handling in httpclient has completely changed.
             * Work around a bug from the HttpClient library */
            ((PostMethod) this.method).setRequestBody("");
        } else {
            throw new ConfigurationException("Invalid method \"" + method + "\" specified"
                    + " at " + configuration.getChild("method").getLocation());
        }

        /* Create the base URL */
        String url = configuration.getChild("url").getValue(null);
        try {
            if (url != null) this.url = new HttpURL(url);
        } catch (URIException e) {
            throw new ConfigurationException("Cannot process URL \"" + url + "\" specified"
                    + " at " + configuration.getChild("url").getLocation());
        }

        /* Prepare the base request and query parameters */
        this.reqParams = this.getParams(configuration.getChildren("param"));
        this.qryParams = this.getParams(configuration.getChildren("query"));
    }

    /**
     * Setup this <code>Generator</code> with its runtime configurations and parameters
     * specified in the sitemap, and prepare it for generation.
     *
     * @param sourceResolver The <code>SourceResolver</code> instance resolving sources by
     *                       system identifiers.
     * @param objectModel The Cocoon "object model" <code>Map</code>
     * @param parameters The runtime <code>Parameters</code> instance.
     * @throws ProcessingException If this instance could not be setup.
     * @throws SAXException If a SAX error occurred during setup.
     * @throws IOException If an I/O error occurred during setup.
     * @see #recycle()
     */
    public void setup(SourceResolver sourceResolver, Map objectModel,
            String source, Parameters parameters)
    throws ProcessingException, SAXException, IOException {
        /* Do the usual stuff */
        super.setup(sourceResolver, objectModel, source, parameters);

        /*
         * Parameter handling: In case the method is a POST method, query
         * parameters and request parameters will be two different arrays
         * (one for the body, one for the query string, otherwise it's going
         * to be the same one, as all parameters are passed on the query string
         */
        ArrayList req = new ArrayList();
        ArrayList qry = req;
        if (this.method instanceof PostMethod) qry = new ArrayList();
        req.addAll(this.reqParams);
        qry.addAll(this.qryParams);

        /*
         * Parameter handling: complete or override the configured parameters with
         * those specified in the pipeline.
         */
        String names[] = parameters.getNames();
        for (int x = 0; x < names.length; x++) {
            String name = names[x];
            String value = parameters.getParameter(name, null);
            if (value == null) continue;

            if (name.startsWith("query:")) {
                name = name.substring("query:".length());
                qry.add(new NameValuePair(name, value));
            } else if (name.startsWith("param:")) {
                name = name.substring("param:".length());
                req.add(new NameValuePair(name, value));
            } else if (name.startsWith("query-override:")) {
                name = name.substring("query-override:".length());
                qry = overrideParams(qry, name, value);
            } else if (name.startsWith("param-override:")) {
                name = name.substring("param-override:".length());
                req = overrideParams(req, name, value);
            }
        }

        /* Process the current source URL in relation to the configured one */
        HttpURL src = (super.source == null ? null : new HttpURL(super.source));
        if (this.url != null) src = (src == null ? this.url : new HttpURL(this.url, src));
        if (src == null) throw new ProcessingException("No URL specified");
        if (src.isRelativeURI()) {
            throw new ProcessingException("Invalid URL \"" + src.toString() + "\"");
        }

        /* Configure the method with the resolved URL */
        HostConfiguration hc = new HostConfiguration();
        hc.setHost(src);
        this.method.setHostConfiguration(hc);
        this.method.setPath(src.getPath());
        this.method.setQueryString(src.getQuery());

        /* And now process the query string (from the parameters above) */
        if (qry.size() > 0) {
            String qs = this.method.getQueryString();
            NameValuePair nvpa[] = new NameValuePair[qry.size()];
            this.method.setQueryString((NameValuePair []) qry.toArray(nvpa));
            if (qs != null) {
                this.method.setQueryString(qs + "&" + this.method.getQueryString());
            }
        }

        /* Finally process the body parameters */
        if ((this.method instanceof PostMethod) && (req.size() > 0)) {
            PostMethod post = (PostMethod) this.method;
            NameValuePair nvpa[] = new NameValuePair[req.size()];
            post.setRequestBody((NameValuePair []) req.toArray(nvpa));
        }

        /* Check the debugging flag */
        this.debug = parameters.getParameterAsBoolean("debug", false);
    }

    /**
     * Recycle this instance, clearing all done during setup and generation, and reverting
     * back to what was configured in the sitemap.
     *
     * @see #configure(Configuration)
     * @see #setup(SourceResolver, Map, String, Parameters)
     * @see #generate()
     */
    public void recycle() {
        /* Recycle the method */
        this.method.recycle();
        /* TODO: Is this still needed? Does it refer to a bug in bugzilla?
         *       At least the handling in httpclient has completely changed.
         *  Work around a bug from the HttpClient library */
        if (this.method instanceof PostMethod) ((PostMethod) this.method).setRequestBody("");

        /* Clean up our parent */
        super.recycle();
    }

    /**
     * Parse the remote <code>InputStream</code> accessed over HTTP.
     *
     * @throws ResourceNotFoundException If the remote HTTP resource could not be found.
     * @throws ProcessingException If an error occurred processing generation.
     * @throws SAXException If an error occurred parsing or processing XML in the pipeline.
     * @throws IOException If an I/O error occurred accessing the HTTP server.
     */
    public void generate()
    throws ResourceNotFoundException, ProcessingException, SAXException, IOException {
        /* Do the boring stuff in case we have to do a debug output (blablabla) */
        if (this.debug) {
            this.generateDebugOutput();
            return;
        }

        /* Call up the remote HTTP server */
        HttpConnection connection = new HttpConnection(this.method.getHostConfiguration());
        HttpState state = new HttpState();
        this.method.setFollowRedirects(true);
        int status = this.method.execute(state, connection);
        if (status == 404) {
            throw new ResourceNotFoundException("Unable to access \"" + this.method.getURI()
                    + "\" (HTTP 404 Error)");
        } else if ((status < 200) || (status > 299)) {
            throw new IOException("Unable to access HTTP resource at \""
                    + this.method.getURI().toString() + "\" (status=" + status + ")");
        }
        InputStream response = this.method.getResponseBodyAsStream();

        /* Let's try to set up our InputSource from the response output stream and to parse it */
        SAXParser parser = null;
        try {
            InputSource inputSource = new InputSource(response);
            parser = (SAXParser) this.manager.lookup(SAXParser.ROLE);
            parser.parse(inputSource, super.xmlConsumer);
        } catch (ServiceException ex) {
            throw new ProcessingException("Unable to get parser", ex);
        } finally {
            this.manager.release(parser);
            this.method.releaseConnection();
            connection.close();
        }
    }

    /**
     * Generate debugging output as XML data from the current configuration.
     *
     * @throws SAXException If an error occurred parsing or processing XML in the pipeline.
     * @throws IOException If an I/O error occurred accessing the HTTP server.
     */
    private void generateDebugOutput()
    throws SAXException, IOException {
        super.xmlConsumer.startDocument();

        AttributesImpl attributes = new AttributesImpl();
        attributes.addAttribute("", "method", "method", "CDATA", this.method.getName());
        attributes.addAttribute("", "url", "url", "CDATA", this.method.getURI().toString());
        attributes.addAttribute("", "protocol", "protocol", "CDATA",
                (this.method.isHttp11() ? "HTTP/1.1" : "HTTP/1.0"));
        super.xmlConsumer.startElement("", "request", "request", attributes);

        if (this.method instanceof PostMethod) {
            String body = ((PostMethod) this.method).getRequestBodyAsString();

            attributes = new AttributesImpl();
            attributes.addAttribute("", "name", "name", "CDATA", "Content-Type");
            attributes.addAttribute("", "value", "value", "CDATA", "application/x-www-form-urlencoded");
            super.xmlConsumer.startElement("", "header", "header", attributes);
            super.xmlConsumer.endElement("", "header", "header");

            attributes = new AttributesImpl();
            attributes.addAttribute("", "name", "name", "CDATA", "Content-Length");
            attributes.addAttribute("", "value", "value", "CDATA", Integer.toString(body.length()));
            super.xmlConsumer.startElement("", "header", "header", attributes);
            super.xmlConsumer.endElement("", "header", "header");

            attributes = new AttributesImpl();
            super.xmlConsumer.startElement("", "body", "body", attributes);
            super.xmlConsumer.characters(body.toCharArray(), 0, body.length());
            super.xmlConsumer.endElement("", "body", "body");
        }

        super.xmlConsumer.endElement("", "request", "request");

        super.xmlConsumer.endDocument();
        return;
    }

    /**
     * Prepare a map of parameters from an array of <code>Configuration</code>
     * items.
     *
     * @param configurations An array of <code>Configuration</code> elements.
     * @return A <code>List</code> of <code>NameValuePair</code> elements.
     * @throws ConfigurationException If a parameter doesn't specify a name.
     */
    private ArrayList getParams(Configuration configurations[])
    throws ConfigurationException {
        ArrayList list = new ArrayList();

        if (configurations.length < 1) return (list);

        for (int x = 0; x < configurations.length; x++) {
            Configuration configuration = configurations[x];
            String name = configuration.getAttribute("name", null);
            if (name == null) {
                throw new ConfigurationException("No name specified for parameter at "
                        + configuration.getLocation());
            }

            String value = configuration.getAttribute("value", null);
            if (value != null) list.add(new NameValuePair(name, value));

            Configuration subconfigurations[] = configuration.getChildren("value");
            for (int y = 0; y < subconfigurations.length; y++) {
                value = subconfigurations[y].getValue(null);
                if (value != null) list.add(new NameValuePair(name, value));
            }
        }
       
        return (list);
    }

    /**
     * Override the value for a named parameter in a specfied <code>ArrayList</code>
     * or add it if the parameter was not found.
     *
     * @param list The <code>ArrayList</code> where the parameter is stored.
     * @param name The parameter name.
     * @param value The new parameter value.
     * @return The same <code>List</code> of <code>NameValuePair</code> elements.
     */
    private ArrayList overrideParams(ArrayList list, String name, String value) {
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            NameValuePair param = (NameValuePair) iterator.next();
            if (param.getName().equals(name)) {
                iterator.remove();
                break;
            }
        }
        list.add(new NameValuePair(name, value));
        return (list);
    }
}
TOP

Related Classes of org.apache.cocoon.generation.HttpProxyGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.