/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.wfs.v1_1_0; import static net.opengis.wfs.ResultTypeType.HITS_LITERAL; import static net.opengis.wfs.ResultTypeType.RESULTS_LITERAL; import static org.geotools.data.wfs.protocol.wfs.GetFeature.ResultType.RESULTS; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; import java.math.BigInteger; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.logging.Logger; import net.opengis.wfs.GetFeatureType; import net.opengis.wfs.QueryType; import net.opengis.wfs.WfsFactory; import org.geotools.data.Query; import org.geotools.data.wfs.protocol.wfs.GetFeature; import org.geotools.data.wfs.protocol.wfs.WFSOperationType; import org.geotools.data.wfs.protocol.wfs.WFSProtocol; import org.geotools.data.wfs.protocol.wfs.GetFeature.ResultType; import org.geotools.factory.GeoTools; import org.geotools.filter.Capabilities; import org.geotools.filter.v1_1.OGC; import org.geotools.filter.v1_1.OGCConfiguration; import org.geotools.filter.visitor.CapabilitiesFilterSplitter; import org.geotools.util.logging.Logging; import org.geotools.wfs.v1_1.WFSConfiguration; import org.geotools.xml.Configuration; import org.geotools.xml.Encoder; import org.opengis.filter.Filter; import org.opengis.filter.Id; import org.opengis.filter.identity.Identifier; import org.opengis.filter.sort.SortBy; /** * A default strategy for a WFS 1.1.0 implementation that assumes the server sticks to the standard. * * @author Gabriel Roldan (OpenGeo) * @version $Id$ * @since 2.6 * * * @source $URL$ * http://gtsvn.refractions.net/trunk/modules/plugin/wfs/src/main/java/org/geotools/data * /wfs/v1_1_0/DefaultWFSStrategy.java $ */ @SuppressWarnings("nls") public class DefaultWFSStrategy implements WFSStrategy { private static final Logger LOGGER = Logging.getLogger("org.geotools.data.wfs"); protected static final String DEFAULT_OUTPUT_FORMAT = "text/xml; subtype=gml/3.1.1"; private static final Configuration filter_1_1_0_Configuration = new OGCConfiguration(); private static final Configuration wfs_1_1_0_Configuration = new WFSConfiguration(); /** * @see WFSStrategy#supportsGet() */ public boolean supportsGet() { return true; } /** * @see WFSStrategy#supportsPost() */ public boolean supportsPost() { return true; } /** * @return {@code "text/xml; subtype=gml/3.1.1"} * @see WFSProtocol#getDefaultOutputFormat() */ public String getDefaultOutputFormat(WFSProtocol wfs, WFSOperationType operation) { if (WFSOperationType.GET_FEATURE != operation) { throw new UnsupportedOperationException( "Not implemented for other than GET_FEATURE yet"); } Set<String> supportedOutputFormats = wfs.getSupportedGetFeatureOutputFormats(); if (supportedOutputFormats.contains(DEFAULT_OUTPUT_FORMAT)) { return DEFAULT_OUTPUT_FORMAT; } throw new IllegalArgumentException("Server does not support '" + DEFAULT_OUTPUT_FORMAT + "' output format: " + supportedOutputFormats); } /** * Creates the mapping {@link GetFeatureType GetFeature} request for the given {@link Query} and * {@code outputFormat}, and post-processing filter based on the server's stated filter * capabilities. * * @see WFSStrategy#createGetFeatureRequest(WFS_1_1_0_DataStore, WFSProtocol, Query, String) */ @SuppressWarnings("unchecked") public RequestComponents createGetFeatureRequest(WFSProtocol wfs, GetFeature query) throws IOException { final WfsFactory factory = WfsFactory.eINSTANCE; GetFeatureType getFeature = factory.createGetFeatureType(); getFeature.setService("WFS"); getFeature.setVersion(wfs.getServiceVersion().toString()); getFeature.setOutputFormat(query.getOutputFormat()); getFeature.setHandle("GeoTools " + GeoTools.getVersion() + " WFS DataStore"); Integer maxFeatures = query.getMaxFeatures(); if (maxFeatures != null) { getFeature.setMaxFeatures(BigInteger.valueOf(maxFeatures.intValue())); } ResultType resultType = query.getResultType(); getFeature.setResultType(RESULTS == resultType ? RESULTS_LITERAL : HITS_LITERAL); QueryType wfsQuery = factory.createQueryType(); wfsQuery.setTypeName(Collections.singletonList(query.getTypeName())); Filter serverFilter = query.getFilter(); if (!Filter.INCLUDE.equals(serverFilter)) { wfsQuery.setFilter(serverFilter); } String srsName = query.getSrsName(); try { wfsQuery.setSrsName(new URI(srsName)); } catch (URISyntaxException e) { throw new RuntimeException("Can't create a URI from the query CRS: " + srsName, e); } String[] propertyNames = query.getPropertyNames(); boolean retrieveAllProperties = propertyNames == null; if (!retrieveAllProperties) { List propertyName = wfsQuery.getPropertyName(); for (String propName : propertyNames) { propertyName.add(propName); } } SortBy[] sortByList = query.getSortBy(); if (sortByList != null) { for (SortBy sortBy : sortByList) { wfsQuery.getSortBy().add(sortBy); } } getFeature.getQuery().add(wfsQuery); RequestComponents reqParts = new RequestComponents(); reqParts.setServerRequest(getFeature); Map<String, String> parametersForGet = buildGetFeatureParametersForGet(getFeature); reqParts.setKvpParameters(parametersForGet); return reqParts; } @SuppressWarnings("unchecked") protected Map<String, String> buildGetFeatureParametersForGet(GetFeatureType request) throws IOException { Map<String, String> map = new HashMap<String, String>(); map.put("SERVICE", "WFS"); map.put("VERSION", "1.1.0"); map.put("REQUEST", "GetFeature"); map.put("OUTPUTFORMAT", request.getOutputFormat()); if (request.getMaxFeatures() != null) { map.put("MAXFEATURES", String.valueOf(request.getMaxFeatures())); } final QueryType query = (QueryType) request.getQuery().get(0); final String typeName = (String) query.getTypeName().get(0); map.put("TYPENAME", typeName); if (query.getPropertyName().size() > 0) { List<String> propertyNames = query.getPropertyName(); StringBuilder pnames = new StringBuilder(); for (Iterator<String> it = propertyNames.iterator(); it.hasNext();) { pnames.append(it.next()); if (it.hasNext()) { pnames.append(','); } } map.put("PROPERTYNAME", pnames.toString()); } // SRSNAME parameter. Let the server reproject. // TODO: should check if the server supports the required crs URI srsName = query.getSrsName(); if (srsName != null) { map.put("SRSNAME", srsName.toString()); } final Filter filter = query.getFilter(); if (filter != null && Filter.INCLUDE != filter) { if (filter instanceof Id) { final Set<Identifier> identifiers = ((Id) filter).getIdentifiers(); StringBuffer idValues = new StringBuffer(); for (Iterator<Identifier> it = identifiers.iterator(); it.hasNext();) { Object id = it.next().getID(); // REVISIT: should URL encode the id? idValues.append(String.valueOf(id)); if (it.hasNext()) { idValues.append(","); } } map.put("FEATUREID", idValues.toString()); } else { String xmlEncodedFilter = encodeGetFeatureGetFilter(filter); map.put("FILTER", xmlEncodedFilter); } } return map; } /** * Returns a single-line string containing the xml representation of the given filter, as * appropriate for the {@code FILTER} parameter in a GetFeature request. */ protected String encodeGetFeatureGetFilter(final Filter filter) throws IOException { Configuration filterConfig = getFilterConfiguration(); Encoder encoder = new Encoder(filterConfig); // do not write the xml declaration encoder.setOmitXMLDeclaration(true); encoder.setEncoding(Charset.forName("UTF-8")); OutputStream out = new ByteArrayOutputStream(); encoder.encode(filter, OGC.Filter, out); String encoded = out.toString(); encoded = encoded.replaceAll("\n", ""); return encoded; } protected Configuration getFilterConfiguration() { return filter_1_1_0_Configuration; } /** * @see WFSStrategy#getWfsConfiguration() */ public Configuration getWfsConfiguration() { return wfs_1_1_0_Configuration; } /** * Splits the filter provided by the geotools query into the server supported and unsupported * ones. * * @param caps * the server filter capabilities description * @param queryFilter * @return a two-element array where the first element is the supported filter and the second * the one to post-process * @see WFSStrategy#splitFilters(WFS_1_1_0_Protocol, Filter) */ public Filter[] splitFilters(Capabilities caps, Filter queryFilter) { CapabilitiesFilterSplitter splitter = new CapabilitiesFilterSplitter( caps, null, null); queryFilter.accept(splitter, null); Filter server = splitter.getFilterPre(); Filter post = splitter.getFilterPost(); return new Filter[] { server, post }; } }