Package org.geotools.data.wfs

Source Code of org.geotools.data.wfs.WFSFeatureSource

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2008-2014, 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;

import java.io.IOException;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.namespace.QName;

import org.geotools.data.DataSourceException;
import org.geotools.data.DataUtilities;
import org.geotools.data.DiffFeatureReader;
import org.geotools.data.EmptyFeatureReader;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.data.ReTypeFeatureReader;
import org.geotools.data.ResourceInfo;
import org.geotools.data.Transaction;
import org.geotools.data.Transaction.State;
import org.geotools.data.crs.ForceCoordinateSystemFeatureReader;
import org.geotools.data.crs.ReprojectFeatureReader;
import org.geotools.data.store.ContentEntry;
import org.geotools.data.store.ContentFeatureSource;
import org.geotools.data.wfs.internal.GetFeatureParser;
import org.geotools.data.wfs.internal.GetFeatureRequest;
import org.geotools.data.wfs.internal.GetFeatureRequest.ResultType;
import org.geotools.data.wfs.internal.GetFeatureResponse;
import org.geotools.data.wfs.internal.WFSClient;
import org.geotools.data.wfs.internal.WFSConfig;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.factory.Hints;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.gml2.bindings.GML2EncodingUtils;
import org.geotools.util.logging.Logging;
import org.opengis.feature.FeatureVisitor;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import com.vividsolutions.jts.geom.CoordinateSequenceFactory;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.impl.PackedCoordinateSequenceFactory;

class WFSFeatureSource extends ContentFeatureSource {

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

    private final WFSClient client;

    public WFSFeatureSource(final ContentEntry entry, final WFSClient client) {
        super(entry, null);
        this.client = client;
    }

    WFSClient getWfs() {
        return client;
    }

    @Override
    protected boolean handleVisitor(Query query, FeatureVisitor visitor) throws IOException {
        return false;
    }

    @Override
    protected boolean canReproject() {
        return true;
    }

    @Override
    protected boolean canOffset() {
        return false;// TODO: check with the WFS client
    }

    /**
     * @return {@code true}
     * @see org.geotools.data.store.ContentFeatureSource#canSort()
     */
    @Override
    protected boolean canSort() {
        return client.canSort();
    }

    /**
     * @return {@code true}
     * @see org.geotools.data.store.ContentFeatureSource#canRetype()
     */
    @Override
    protected boolean canRetype() {
        return client.canRetype();
    }

    /**
     * @return {@code true}
     * @see org.geotools.data.store.ContentFeatureSource#canFilter()
     */
    @Override
    protected boolean canFilter() {
        return client.canFilter();
    }

    /**
     * @return {@code true}
     * @see org.geotools.data.store.ContentFeatureSource#canLimit()
     */
    @Override
    protected boolean canLimit() {
        return client.canLimit();
    }

    @Override
    public WFSDataStore getDataStore() {
        return (WFSDataStore) super.getDataStore();
    }

    /**
     * @return the WFS advertised bounds of the feature type if
     *         {@code Filter.INCLUDE ==  query.getFilter()}, reprojected to the Query's crs, or
     *         {@code null} otherwise as it would be too expensive to calculate.
     * @see FeatureSource#getBounds(Query)
     * @see org.geotools.data.store.ContentFeatureSource#getBoundsInternal(org.geotools.data.Query)
     */
    @Override
    protected ReferencedEnvelope getBoundsInternal(Query query) throws IOException {
        if (!Filter.INCLUDE.equals(query.getFilter())) {
            return null;
        }

        final QName remoteTypeName = getRemoteTypeName();

        final CoordinateReferenceSystem targetCrs;
        if (null == query.getCoordinateSystem()) {
            targetCrs = client.getDefaultCRS(remoteTypeName);
        } else {
            targetCrs = query.getCoordinateSystem();
        }

        ReferencedEnvelope bounds = client.getBounds(remoteTypeName, targetCrs);
        return bounds;
    }

    /**
     * @return the remote WFS advertised number of features for the given query only if the query
     *         filter is fully supported AND the wfs returns that information in as an attribute of
     *         the FeatureCollection (since the request is performed with resultType=hits),
     *         otherwise {@code -1} as it would be too expensive to calculate.
     * @see FeatureSource#getCount(Query)
     * @see org.geotools.data.store.ContentFeatureSource#getCountInternal(org.geotools.data.Query)
     */
    @Override
    protected int getCountInternal(Query query) throws IOException {
        if (!client.canCount()) {
            return -1;
        }

        GetFeatureRequest request = createGetFeature(query, ResultType.HITS);

        GetFeatureResponse response = client.issueRequest(request);
        GetFeatureParser featureParser = response.getFeatures(null);
        int resultCount = featureParser.getNumberOfFeatures();
        return resultCount;
    }
   
    /**
     * Invert axis order in the given query filter, if needed.
     *
     * @param query
     */
    private void invertAxisInFilterIfNeeded(Query query) {
        boolean invertXY = WFSConfig.invertAxisNeeded(client.getAxisOrderFilter(), query.getCoordinateSystem());
        if (invertXY) {
            Filter filter = query.getFilter();
   
            FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
            InvertAxisFilterVisitor visitor = new InvertAxisFilterVisitor(ff, new GeometryFactory());
            filter = (Filter) filter.accept(visitor, null);
   
            query.setFilter(filter);
        }
    }

    private GetFeatureRequest createGetFeature(Query query, ResultType resultType)
            throws IOException {
        GetFeatureRequest request = client.createGetFeatureRequest();

        final WFSDataStore dataStore = getDataStore();

        final QName remoteTypeName = dataStore.getRemoteTypeName(getEntry().getName());
        final SimpleFeatureType remoteSimpleFeatureType;
        remoteSimpleFeatureType = dataStore.getRemoteSimpleFeatureType(remoteTypeName);

        request.setTypeName(remoteTypeName);
        request.setFullType(remoteSimpleFeatureType);
       
        invertAxisInFilterIfNeeded(query);

        request.setFilter(query.getFilter());
        request.setResultType(resultType);
        int maxFeatures = query.getMaxFeatures();
        if (Integer.MAX_VALUE > maxFeatures) {
            request.setMaxFeatures(maxFeatures);
        }
        // let the request decide request.setOutputFormat(outputFormat);
        request.setPropertyNames(query.getPropertyNames());
        request.setSortBy(query.getSortBy());

        String srsName = getSupportedSrsName(request, query)
       
        request.setSrsName(srsName);
        return request;
    }

    /**
     * @see FeatureSource#getFeatures(Query)
     * @see org.geotools.data.store.ContentFeatureSource#getReaderInternal(org.geotools.data.Query)
     */
    @Override
    protected FeatureReader<SimpleFeatureType, SimpleFeature> getReaderInternal(Query localQuery)
            throws IOException {

        if (Filter.EXCLUDE.equals(localQuery.getFilter())) {
            return new EmptyFeatureReader<SimpleFeatureType, SimpleFeature>(getSchema());
        }

        GetFeatureRequest request = createGetFeature(localQuery, ResultType.RESULTS);

        final SimpleFeatureType destType = getQueryType(localQuery, getSchema());
        final SimpleFeatureType contentType = getQueryType(localQuery, (SimpleFeatureType) request.getFullType());
        request.setQueryType(contentType);

        GetFeatureResponse response = client.issueRequest(request);

        GeometryFactory geometryFactory = findGeometryFactory(localQuery.getHints());
        GetFeatureParser features = response.getSimpleFeatures(geometryFactory);

        FeatureReader<SimpleFeatureType, SimpleFeature> reader;
        reader = new WFSFeatureReader(features);

        if (!reader.hasNext()) {
            return new EmptyFeatureReader<SimpleFeatureType, SimpleFeature>(contentType);
        }

        final SimpleFeatureType readerType = reader.getFeatureType();
        if (!destType.equals(readerType)) {
            final boolean cloneContents = false;
            reader = new ReTypeFeatureReader(reader, destType, cloneContents);
        }
       
        reader = applyReprojectionDecorator(reader, localQuery, request);

        Transaction transaction = getTransaction();
        if (!Transaction.AUTO_COMMIT.equals(transaction)) {
            ContentEntry entry = getEntry();
            State state = transaction.getState(entry);
            WFSLocalTransactionState wfsState = (WFSLocalTransactionState) state;
            if (wfsState != null) {
                WFSDiff diff = wfsState.getDiff();
                reader = new DiffFeatureReader<SimpleFeatureType, SimpleFeature>(reader, diff, localQuery.getFilter());
            }
        }
        return reader;
    }
   
    protected String getSupportedSrsName(GetFeatureRequest request, Query query) {
        String epsgCode = GML2EncodingUtils.epsgCode(query.getCoordinateSystem());
        Set<String> supported = request.getStrategy().getSupportedCRSIdentifiers(request.getTypeName());
        for (String supportedSrs : supported) {
            if (supportedSrs.endsWith(":" + epsgCode)) {
                return supportedSrs;
            }
        }
        return null;
    }
   
    protected  FeatureReader<SimpleFeatureType, SimpleFeature> applyReprojectionDecorator(FeatureReader <SimpleFeatureType, SimpleFeature> reader, Query query, GetFeatureRequest request) {
         FeatureReader<SimpleFeatureType, SimpleFeature> tmp = reader;
        if (query.getCoordinateSystem() != null
                && !query.getCoordinateSystem().equals(reader.getFeatureType().getCoordinateReferenceSystem())) {
            if (request.getSrsName() != null) {
                try {
                    reader = new ForceCoordinateSystemFeatureReader(reader, query.getCoordinateSystem());
                } catch (SchemaException e) {
                    LOGGER.warning(e.toString());
                    reader = tmp;
                }
            } else {
                try {
                    reader = new ReprojectFeatureReader(reader, query.getCoordinateSystem());
                } catch (Exception e) {
                    LOGGER.warning(e.toString());
                    reader = tmp;
                }
            }
        }
        return reader;
    }

    private GeometryFactory findGeometryFactory(Hints hints) {
        GeometryFactory geomFactory = (GeometryFactory) hints.get(Hints.JTS_GEOMETRY_FACTORY);
        if (geomFactory == null) {
            CoordinateSequenceFactory seqFac;
            seqFac = (CoordinateSequenceFactory) hints.get(Hints.JTS_COORDINATE_SEQUENCE_FACTORY);
            if (seqFac == null) {
                seqFac = PackedCoordinateSequenceFactory.DOUBLE_FACTORY;
            }
            geomFactory = new GeometryFactory(seqFac);
        }
        return geomFactory;
    }

    @Override
    protected SimpleFeatureType buildFeatureType() throws IOException {
        final WFSDataStore dataStore = getDataStore();

        final Name localTypeName = getEntry().getName();
        final QName remoteTypeName = dataStore.getRemoteTypeName(localTypeName);

        final SimpleFeatureType remoteSimpleFeatureType;
        remoteSimpleFeatureType = dataStore.getRemoteSimpleFeatureType(remoteTypeName);

        // adapt the feature type name
        SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
        builder.init(remoteSimpleFeatureType);
        builder.setName(localTypeName);
        String namespaceOverride = entry.getName().getNamespaceURI();

        if (namespaceOverride != null) {
            builder.setNamespaceURI(namespaceOverride);
        }

        GeometryDescriptor defaultGeometry = remoteSimpleFeatureType.getGeometryDescriptor();
        if (defaultGeometry != null) {
            builder.setDefaultGeometry(defaultGeometry.getLocalName());
            builder.setCRS(defaultGeometry.getCoordinateReferenceSystem());
        }
        final SimpleFeatureType adaptedFeatureType = builder.buildFeatureType();
        return adaptedFeatureType;
    }

    public QName getRemoteTypeName() throws IOException {
        Name localTypeName = getEntry().getName();
        QName remoteTypeName = getDataStore().getRemoteTypeName(localTypeName);
        return remoteTypeName;
    }

    /**
     * Returns the feature type that shall result of issueing the given request, adapting the
     * original feature type for the request's type name in terms of the query CRS and requested
     * attributes.
     *
     * @param query
     * @return
     * @throws IOException
     */
    SimpleFeatureType getQueryType(final Query query, SimpleFeatureType featureType) throws IOException {

        final CoordinateReferenceSystem coordinateSystemReproject = query
                .getCoordinateSystemReproject();

        String[] propertyNames = query.getPropertyNames();

        SimpleFeatureType queryType = featureType;
        if (propertyNames != null && propertyNames.length > 0) {
            try {
                queryType = DataUtilities.createSubType(queryType, propertyNames);
            } catch (SchemaException e) {
                throw new DataSourceException(e);
            }
        } else {
            propertyNames = DataUtilities.attributeNames(featureType);
        }

        if (coordinateSystemReproject != null) {
            try {
                queryType = DataUtilities.createSubType(queryType, propertyNames,
                        coordinateSystemReproject);
            } catch (SchemaException e) {
                throw new DataSourceException(e);
            }
        }

        return queryType;
    }
   
    @Override
    public ResourceInfo getInfo() {
        try {
            return client.getInfo(getRemoteTypeName());
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "Unexpected error getting ResourceInfo: ", e);
            return super.getInfo();
        }
    }

}
TOP

Related Classes of org.geotools.data.wfs.WFSFeatureSource

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.