All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotools.data.ows.AbstractOpenWebService Maven / Gradle / Ivy

Go to download

The main module contains the GeoTools public interfaces that are used by other GeoTools modules (and GeoTools applications). Where possible we make use industry standard terms as provided by OGC and ISO standards. The formal GeoTools public api consists of gt-metadata, jts and the gt-main module. The main module contains the default implementations that are available provided to other GeoTools modules using our factory system. Factories are obtained from an appropriate FactoryFinder, giving applications a chance configure the factory used using the Factory Hints facilities. FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expr = ff.add( expression1, expression2 ); If you find yourself using implementation specific classes chances are you doing it wrong: Expression expr = new AddImpl( expression1, expressiom2 );

There is a newer version: 24.2-oss84-1
Show newest version
/*
 *    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 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 an Open Web Service (OWS)
 * client. Each OWS is usually defined by an OGC specification, available at http://www.opengeospatial.org.
 *
 * 

This class provides version negotiation, Capabilities document retrieval, and a * request/response infrastructure. Implementing subclasses need to provide their own Specifications * (representing versions of the OWS to be implemented) and their own request/response instances. * * @author Richard Gould */ public abstract class AbstractOpenWebService { private HTTPClient httpClient; protected final URL serverURL; protected C capabilities; protected ServiceInfo info; protected Map resourceInfo = new HashMap(); /** Contains the specifications that are to be used with this service */ protected Specification[] specs; protected Specification specification; /** Hints, now used for the XML parsing * */ protected Map hints; protected static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger(AbstractOpenWebService.class); /** * 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 AbstractOpenWebService(final URL serverURL) throws IOException, ServiceException { this(serverURL, new SimpleHttpClient(), null); } public AbstractOpenWebService( final URL serverURL, final HTTPClient httpClient, final C capabilities) throws ServiceException, IOException { this(serverURL, httpClient, capabilities, null); } public AbstractOpenWebService( final URL serverURL, final HTTPClient httpClient, final C capabilities, Map hints) throws ServiceException, IOException { if (serverURL == null) { throw new NullPointerException("serverURL"); } if (httpClient == null) { throw new NullPointerException("httpClient"); } this.serverURL = serverURL; this.httpClient = httpClient; this.hints = hints; setupSpecifications(); if (capabilities == null) { this.capabilities = negotiateVersion(); if (this.capabilities == null) { throw new ServiceException( "Version negotiation unable to retrieve or parse Capabilities document."); } } else { this.capabilities = capabilities; } for (int i = 0; i < specs.length; i++) { if (specs[i].getVersion().equals(this.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; } /** * Get the getCapabilities document. If there was an error parsing it during creation, it will * return null (and it should have thrown an exception during creation). * * @return a Capabilities object, representing the Capabilities of the server */ public abstract C getCapabilities(); /** * Description of this service. * *

Provides a very quick description of the service, for more information please review the * capabilitie document. * *

* * @return description of this service. */ public ServiceInfo getInfo() { if (capabilities == null) { return null; } 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) { if (capabilities == null) { return null; } synchronized (capabilities) { if (!resourceInfo.containsKey(resource)) { resourceInfo.put(resource, createInfo(resource)); } } return resourceInfo.get(resource); } protected abstract ResourceInfo createInfo(R resource); /** Sets up the specifications/versions that this server is capable of communicating with. */ protected abstract void setupSpecifications(); /** * Version number negotiation occurs as follows (credit OGC): * *

    *
  • 1) If the server implements the requested version number, the server shall send * that version. *
  • 2a) If a version unknown to the server is requested, the server shall send the * highest version less than the requested version. *
  • 2b) 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. *
  • 3a) 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). *
  • 3b) 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. *
* *

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 */ @SuppressWarnings("unchecked") 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; // Respect Version if provided in URL (GEOT-3361 ) if (serverURL.getQuery() != null) { String[] tokens = serverURL.getQuery().split("&"); for (String token : tokens) { String[] param = token.split("="); if (param != null && param.length > 1 && param[0] != null && param[0].equalsIgnoreCase("version")) { if (versions.contains(param[1])) test = versions.indexOf(param[1]); } } } while ((minClient <= test) && (test <= maxClient)) { Specification tempSpecification = specs[test]; String clientVersion = tempSpecification.getVersion(); GetCapabilitiesRequest request = tempSpecification.createGetCapabilitiesRequest(serverURL); request.setRequestHints(hints); // 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( "Could not establish version neogitation: " + exception.getMessage(), exception); throw e; } else { throw new ServiceException( "Version negotiation unable to retrieve or parse Capabilities document."); } } /** * Utility method returning the known version, just before the provided version * * @param known List 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 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(); LOGGER.fine("FinalURL:" + finalURL); boolean success = false; try { final HTTPResponse httpResponse; if (request.requiresPost()) { final String postContentType = request.getPostContentType(); ByteArrayOutputStream out = new ByteArrayOutputStream(); request.performPostOutput(out); InputStream in; if (LOGGER.isLoggable(Level.FINE)) { byte[] byteArray = out.toByteArray(); LOGGER.fine(new String(byteArray)); in = new ByteArrayInputStream(byteArray); } else { 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); success = true; if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Executed request to URL: " + finalURL.toExternalForm()); } return response; } finally { if (!success) { LOGGER.log(Level.SEVERE, "Failed to execute request " + finalURL); } } } public GetCapabilitiesResponse issueRequest(GetCapabilitiesRequest request) throws IOException, ServiceException { return (GetCapabilitiesResponse) internalIssueRequest(request); } public void setLoggingLevel(Level newLevel) { LOGGER.setLevel(newLevel); } /** Returns the hints affecting the service operations */ public Map getHints() { return hints; } /** Sets the hints affecting the service operations */ public void setHints(Map hints) { this.hints = hints; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy