org.geoserver.wps.executor.RemoteRequestInputProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.geoserver.wps.executor.RemoteRequestInputProvider.java

Source

/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
 * This code is licensed under the GPL 2.0 license, available at the root
 * application directory.
 */
package org.geoserver.wps.executor;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.opengis.wps10.HeaderType;
import net.opengis.wps10.InputReferenceType;
import net.opengis.wps10.InputType;
import net.opengis.wps10.MethodType;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.geoserver.wps.WPSException;
import org.geoserver.wps.ppio.ComplexPPIO;
import org.geotools.data.DataUtilities;
import org.geotools.util.logging.Logging;
import org.opengis.util.ProgressListener;

/**
 * Handles an internal reference to a remote location
 * 
 * @author Andrea Aime - GeoSolutions
 */
public class RemoteRequestInputProvider extends AbstractInputProvider {

    static final Logger LOGGER = Logging.getLogger(RemoteRequestInputProvider.class);

    private int timeout;

    private ComplexPPIO complexPPIO;

    private long maxSize;

    public RemoteRequestInputProvider(InputType input, ComplexPPIO ppio, int timeout, long maxSize) {
        super(input, ppio);
        this.timeout = timeout;
        this.complexPPIO = ppio;
        this.maxSize = maxSize;
    }

    @Override
    protected Object getValueInternal(ProgressListener listener) throws Exception {
        InputReferenceType ref = input.getReference();
        URL destination = new URL(ref.getHref());

        HttpMethod method = null;
        GetMethod refMethod = null;
        InputStream input = null;
        InputStream refInput = null;

        // execute the request
        listener.started();
        try {
            if ("file".equalsIgnoreCase(destination.getProtocol())) {
                File file = DataUtilities.urlToFile(destination);
                if (maxSize > 0 && maxSize < file.length()) {
                    throw new WPSException("Input " + getInputId() + " size " + file.length()
                            + " exceeds maximum allowed size of " + maxSize, "NoApplicableCode", getInputId());
                }

                input = new FileInputStream(file);
            } else if ("http".equalsIgnoreCase(destination.getProtocol())) {
                // setup the client
                HttpClient client = new HttpClient();
                // setting timeouts (30 seconds, TODO: make this configurable)
                HttpConnectionManagerParams params = new HttpConnectionManagerParams();
                params.setSoTimeout(timeout);
                params.setConnectionTimeout(timeout);
                // TODO: make the http client a well behaved http client, no more than x connections
                // per server (x admin configurable maybe), persistent connections and so on
                HttpConnectionManager manager = new SimpleHttpConnectionManager();
                manager.setParams(params);
                client.setHttpConnectionManager(manager);

                // prepare either a GET or a POST request
                if (ref.getMethod() == null || ref.getMethod() == MethodType.GET_LITERAL) {
                    GetMethod get = new GetMethod(ref.getHref());
                    get.setFollowRedirects(true);
                    method = get;
                } else {
                    String encoding = ref.getEncoding();
                    if (encoding == null) {
                        encoding = "UTF-8";
                    }

                    PostMethod post = new PostMethod(ref.getHref());
                    Object body = ref.getBody();
                    if (body == null) {
                        if (ref.getBodyReference() != null) {
                            URL refDestination = new URL(ref.getBodyReference().getHref());
                            if ("http".equalsIgnoreCase(refDestination.getProtocol())) {
                                // open with commons http client
                                refMethod = new GetMethod(ref.getBodyReference().getHref());
                                refMethod.setFollowRedirects(true);
                                client.executeMethod(refMethod);
                                refInput = refMethod.getResponseBodyAsStream();
                            } else {
                                // open with the built-in url management
                                URLConnection conn = refDestination.openConnection();
                                conn.setConnectTimeout(timeout);
                                conn.setReadTimeout(timeout);
                                refInput = conn.getInputStream();
                            }
                            post.setRequestEntity(
                                    new InputStreamRequestEntity(refInput, complexPPIO.getMimeType()));
                        } else {
                            throw new WPSException("A POST request should contain a non empty body");
                        }
                    } else if (body instanceof String) {
                        post.setRequestEntity(
                                new StringRequestEntity((String) body, complexPPIO.getMimeType(), encoding));
                    } else {
                        throw new WPSException("The request body should be contained in a CDATA section, "
                                + "otherwise it will get parsed as XML instead of being preserved as is");

                    }
                    method = post;
                }
                // add eventual extra headers
                if (ref.getHeader() != null) {
                    for (Iterator it = ref.getHeader().iterator(); it.hasNext();) {
                        HeaderType header = (HeaderType) it.next();
                        method.setRequestHeader(header.getKey(), header.getValue());
                    }
                }
                int code = client.executeMethod(method);

                if (code == 200) {
                    try {
                        Header length = method.getResponseHeader("Content-Lenght");
                        if (maxSize > 0 && length != null && Long.parseLong(length.getValue()) > maxSize) {
                            throw new WPSException(
                                    "Input " + getInputId() + " size " + length.getValue()
                                            + " exceeds maximum allowed size of " + maxSize
                                            + " according to HTTP Content-Lenght response header",
                                    "NoApplicableCode", getInputId());
                        }
                    } catch (NumberFormatException e) {
                        LOGGER.log(Level.FINE, "Failed to parse content lenght to check input limits respect, "
                                + "moving on and checking data as it comes in", e);
                    }
                    input = method.getResponseBodyAsStream();
                    if (maxSize > 0) {
                        input = new MaxSizeInputStream(input, getInputId(), maxSize);
                    }
                } else {
                    throw new WPSException("Error getting remote resources from " + ref.getHref() + ", http error "
                            + code + ": " + method.getStatusText());
                }
            } else {
                // use the normal url connection methods then...
                URLConnection conn = destination.openConnection();
                conn.setConnectTimeout(timeout);
                conn.setReadTimeout(timeout);
                input = conn.getInputStream();

                if (maxSize > 0) {
                    input = new MaxSizeInputStream(input, getInputId(), maxSize);
                }
            }

            // actually parse the data
            if (input != null) {
                CancellingInputStream is = new CancellingInputStream(input, listener);
                return complexPPIO.decode(is);
            } else {
                throw new WPSException("Could not find a mean to read input " + inputId);
            }
        } finally {
            listener.progress(100);
            listener.complete();
            // make sure to close the connection and streams no matter what
            if (refInput != null) {
                refInput.close();
            }
            if (input != null) {
                input.close();
            }
            if (method != null) {
                method.releaseConnection();
            }
            if (refMethod != null) {
                refMethod.releaseConnection();
            }
        }
    }

    @Override
    public int longStepCount() {
        return 1;
    }

}