Package org.geotools.data.ows

Source Code of org.geotools.data.ows.AbstractWPS

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2004-2008, Open Source Geospatial Foundation (OSGeo)
*
*    This library is free software; you can redistribute it and/or
*    modify it under the terms of the GNU Lesser General Public
*    License as published by the Free Software Foundation;
*    version 2.1 of the License.
*
*    This library 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
*    Lesser General Public License for more details.
*/
package org.geotools.data.ows;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import net.opengis.wps10.WPSCapabilitiesType;

import org.geotools.data.ResourceInfo;
import org.geotools.data.ServiceInfo;
import org.geotools.ows.ServiceException;


/**
* This abstract class provides a building block for one to implement a
* WPS client.
*
* This class provides version negotiation, Capabilities document retrieval,
* and a request/response infrastructure. Implementing subclasses need to
* provide their own Specifications
*
* @author gdavis
*
*
* @source $URL$
*/
public abstract class AbstractWPS<C extends WPSCapabilitiesType, R extends Object>
{

    private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.ows");
    protected HTTPClient httpClient;
    protected final URL serverURL;
    protected C capabilities;
    protected ServiceInfo info;
    protected Map<R, ResourceInfo> resourceInfo = new HashMap<R, ResourceInfo>();

    /** Contains the specifications that are to be used with this service */
    protected Specification[] specs;
    protected Specification specification;

    /**
     * Set up the specifications used and retrieve the Capabilities document
     * given by serverURL.
     *
     * @param serverURL a URL that points to the capabilities document of a server
     * @throws IOException if there is an error communicating with the server
     * @throws ServiceException if the server responds with an error
     */
    public AbstractWPS(final URL serverURL) throws IOException, ServiceException
    {
        this(serverURL, new SimpleHttpClient(), null);

        capabilities = negotiateVersion();
        if (capabilities == null)
        {
            throw new ServiceException("Unable to retrieve or parse Capabilities document.");
        }
        else if (capabilities != null)
        {
            setupSpecification(capabilities);
        }
    }

    /**
     * @throws IOException
     * @throws ServiceException
     * @deprecated use {@link #AbstractWPS(OWSConfig)}
     */
    public AbstractWPS(final URL serverURL, int requestTimeout) throws ServiceException, IOException
    {
        this(serverURL, new SimpleHttpClient(), null);
        this.httpClient.setConnectTimeout(requestTimeout);
        this.httpClient.setReadTimeout(requestTimeout);
    }

    /**
     * @deprecated use {@link #AbstractWPS(OWSConfig, Capabilities)}
     */
    public AbstractWPS(C capabilties, URL serverURL) throws ServiceException, IOException
    {
        this(serverURL, new SimpleHttpClient(), capabilties);
    }

    public AbstractWPS(final URL serverURL, final HTTPClient httpClient,
        final C capabilities) throws ServiceException, IOException
    {
        if (serverURL == null)
        {
            throw new NullPointerException("serverURL");
        }
        if (httpClient == null)
        {
            throw new NullPointerException("httpClient");
        }

        this.serverURL = serverURL;
        this.httpClient = httpClient;

        setupSpecifications();

        if (capabilities != null)
        {
            setupSpecification(capabilities);

            this.capabilities = capabilities;
        }
        else
        {
            this.capabilities = negotiateVersion();
            if (this.capabilities == null)
            {
                throw new ServiceException("Unable to retrieve or parse Capabilities document.");
            }
            setupSpecification(this.capabilities);
        }

    }

    /**
     * @param capabilities
     */
    private void setupSpecification(final C capabilities)
    {
        for (int i = 0; i < specs.length; i++)
        {
            if (specs[i].getVersion().equals(capabilities.getVersion()))
            {
                specification = specs[i];

                break;
            }
        }

        if (specification == null)
        {
            specification = specs[specs.length - 1];
            LOGGER.warning("Unable to choose a specification based on cached capabilities. " +
                "Arbitrarily choosing spec '" + specification.getVersion() + "'.");
        }
    }

    public void setHttpClient(HTTPClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public HTTPClient getHTTPClient()
    {
        return this.httpClient;
    }

    /**
     * Description of this service.
     * <p>
     * Provides a very quick description of the service, for more information
     * please review the capabilitie document.
     * <p>
     * @return description of  this service.
     */
    public ServiceInfo getInfo()
    {
        synchronized (capabilities)
        {
            if (info == null)
            {
                info = createInfo();
            }

            return info;
        }
    }

    /**
     * Implemented by a subclass to describe service
     * @return ServiceInfo
     */
    protected abstract ServiceInfo createInfo();

    public ResourceInfo getInfo(R resource)
    {
        synchronized (capabilities)
        {
            if (!resourceInfo.containsKey(resource))
            {
                resourceInfo.put(resource, createInfo(resource));
            }
        }

        return resourceInfo.get(resource);
    }

    protected abstract ResourceInfo createInfo(R resource);


    private void syncrhonized(Capabilities capabilities2)
    {
        // TODO Auto-generated method stub
    }

    /**
     * Sets up the specifications/versions that this server is capable of
     * communicating with.
     */
    protected abstract void setupSpecifications();

    /**
     * <p>
     * Version number negotiation occurs as follows (credit OGC):
     * <ul>
     * <li><b>1) </b> If the server implements the requested version number, the server shall send that version.</li>
     * <li><b>2a) </b> If a version unknown to the server is requested, the server shall send the highest version less
     * than the requested version.</li>
     * <li><b>2b) </b> If the client request is for a version lower than any of those known to the server, then the
     * server shall send the lowest version it knows.</li>
     * <li><b>3a) </b> If the client does not understand the new version number sent by the server, it may either cease
     * communicating with the server or send a new request with a new version number that the client does understand but
     * which is less than that sent by the server (if the server had responded with a lower version).</li>
     * <li><b>3b) </b> If the server had responded with a higher version (because the request was for a version lower
     * than any known to the server), and the client does not understand the proposed higher version, then the client
     * may send a new request with a version number higher than that sent by the server.</li>
     * </ul>
     * </p>
     * <p>
     * The OGC tells us to repeat this process (or give up). This means we are
     * actually going to come up with a bit of setup cost in figuring out our
     * GetCapabilities request. This means that it is possible that we may make
     * multiple requests before being satisfied with a response.
     *
     * Also, if we are unable to parse a given version for some reason,
     * for example, malformed XML, we will request a lower version until
     * we have run out of versions to request with. Thus, a server that does
     * not play nicely may take some time to parse and might not even
     * succeed.
     *
     * @return a capabilities object that represents the Capabilities on the server
     * @throws IOException if there is an error communicating with the server, or the XML cannot be parsed
     * @throws ServiceException if the server returns a ServiceException
     */
    protected C negotiateVersion() throws IOException, ServiceException
    {
        List versions = new ArrayList(specs.length);
        Exception exception = null;

        for (int i = 0; i < specs.length; i++)
        {
            versions.add(i, specs[i].getVersion());
        }

        int minClient = 0;
        int maxClient = specs.length - 1;

        int test = maxClient;

        while ((minClient <= test) && (test <= maxClient))
        {
            Specification tempSpecification = specs[test];
            String clientVersion = tempSpecification.getVersion();

            GetCapabilitiesRequest request = tempSpecification.createGetCapabilitiesRequest(serverURL);

            // Grab document
            C tempCapabilities;
            try
            {
                tempCapabilities = (C) issueRequest(request).getCapabilities();
            }
            catch (ServiceException e)
            {
                tempCapabilities = null;
                exception = e;
            }

            int compare = -1;
            String serverVersion = clientVersion; // Ignored if caps is null

            if (tempCapabilities != null)
            {

                serverVersion = tempCapabilities.getVersion();

                compare = serverVersion.compareTo(clientVersion);
            }

            if (compare == 0)
            {
                // we have an exact match and have capabilities as well!
                this.specification = tempSpecification;

                return tempCapabilities;
            }

            if ((tempCapabilities != null) && versions.contains(serverVersion))
            {
                // we can communicate with this server
                int index = versions.indexOf(serverVersion);
                this.specification = specs[index];

                return tempCapabilities;

            }
            else if (compare < 0)
            {
                // server responded lower then we asked - and we don't understand.
                maxClient = test - 1; // set current version as limit

                // lets try and go one lower?
                //
                clientVersion = before(versions, serverVersion);

                if (clientVersion == null)
                {
                    if (exception != null)
                    {
                        if (exception instanceof ServiceException)
                        {
                            throw (ServiceException) exception;
                        }

                        IOException e = new IOException(exception.getMessage());
                        throw e;
                    }

                    return null; // do not know any lower version numbers
                }

                test = versions.indexOf(clientVersion);
            }
            else
            {
                // server responsed higher than we asked - and we don't understand
                minClient = test + 1; // set current version as lower limit

                // lets try and go one higher
                clientVersion = after(versions, serverVersion);

                if (clientVersion == null)
                {
                    if (exception != null)
                    {
                        if (exception instanceof ServiceException)
                        {
                            throw (ServiceException) exception;
                        }

                        IOException e = new IOException(exception.getMessage());
                        throw e;
                    }

                    return null; // do not know any lower version numbers
                }

                test = versions.indexOf(clientVersion);
            }
        }

        // could not talk to this server
        if (exception != null)
        {
            IOException e = new IOException(exception.getMessage());
            throw e;
        }

        return null;
    }

    /**
     * Utility method returning the known version, just before the provided version
     *
     * @param known List<String> of all known versions
     * @param version the boundary condition
     * @return the version just below the provided boundary version
     */
    String before(List known, String version)
    {
        if (known.isEmpty())
        {
            return null;
        }

        String before = null;

        for (Iterator i = known.iterator(); i.hasNext();)
        {
            String test = (String) i.next();

            if (test.compareTo(version) < 0)
            {

                if ((before == null) || (before.compareTo(test) < 0))
                {
                    before = test;
                }
            }
        }

        return before;
    }

    /**
     * Utility method returning the known version, just after the provided version
     *
     * @param known a List<String> of all known versions
     * @param version the boundary condition
     * @return a version just after the provided boundary condition
     */
    String after(List known, String version)
    {
        if (known.isEmpty())
        {
            return null;
        }

        String after = null;

        for (Iterator i = known.iterator(); i.hasNext();)
        {
            String test = (String) i.next();

            if (test.compareTo(version) > 0)
            {
                if ((after == null) || (after.compareTo(test) < 0))
                {
                    after = test;
                }
            }
        }

        return after;
    }

    /**
     * Issues a request to the server and returns that server's response. It
     * asks the server to send the response gzipped to provide a faster transfer
     * time.
     *
     * @param request the request to be issued
     * @return a response from the server, which is created according to the specific Request
     * @throws IOException if there was a problem communicating with the server
     * @throws ServiceException if the server responds with an exception or returns bad content
     */
    protected Response internalIssueRequest(Request request) throws IOException, ServiceException
    {
        final URL finalURL = request.getFinalURL();

        final HTTPResponse httpResponse;

        if (request.requiresPost())
        {

            final String postContentType = request.getPostContentType();

            ByteArrayOutputStream out = new ByteArrayOutputStream();
            request.performPostOutput(out);

            InputStream in = new ByteArrayInputStream(out.toByteArray());

            try
            {
                httpResponse = httpClient.post(finalURL, in, postContentType);
            }
            finally
            {
                in.close();
            }
        }
        else
        {
            httpResponse = httpClient.get(finalURL);
        }

        final Response response = request.createResponse(httpResponse);

        return response;
    }

    public AbstractWPSGetCapabilitiesResponse issueRequest(GetCapabilitiesRequest request) throws IOException,
        ServiceException
    {
        return (AbstractWPSGetCapabilitiesResponse) internalIssueRequest(request);
    }

    public void setLoggingLevel(Level newLevel)
    {
        LOGGER.setLevel(newLevel);
    }
}
TOP

Related Classes of org.geotools.data.ows.AbstractWPS

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.