Package org.vfny.geoserver.wms.responses.featureInfo

Source Code of org.vfny.geoserver.wms.responses.featureInfo.GetFeatureInfoDelegate

/* Copyright (c) 2001, 2003 TOPP - www.openplans.org.  All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.wms.responses.featureInfo;

import java.util.ArrayList;
import java.util.List;

import org.geotools.data.DefaultQuery;
import org.geotools.data.Query;
import org.geotools.feature.FeatureType;
import org.geotools.filter.AbstractFilter;
import org.geotools.filter.BBoxExpression;
import org.geotools.filter.Expression;
import org.geotools.filter.Filter;
import org.geotools.filter.FilterFactory;
import org.geotools.filter.GeometryFilter;
import org.geotools.filter.IllegalFilterException;
import org.vfny.geoserver.Request;
import org.vfny.geoserver.Response;
import org.vfny.geoserver.ServiceException;
import org.vfny.geoserver.global.FeatureTypeInfo;
import org.vfny.geoserver.global.Service;
import org.vfny.geoserver.wms.WmsException;
import org.vfny.geoserver.wms.requests.GetFeatureInfoRequest;

import com.vividsolutions.jts.geom.Envelope;


/**
* Base class for GetFeatureInfo delegates responsible of creating
* GetFeatureInfo responses in different formats.
*
* <p>
* Subclasses should implement one or more output formats, wich will be
* returned in a list of mime type strings in
* <code>getSupportedFormats</code>. For example, a subclass can be created to
* write one of the following output formats:
*
* <ul>
* <li>
* text/plain
* </li>
* <li>
* text/html
* </li>
* </ul>
* </p>
*
* <p>
* This abstract class takes care of executing the request in the sense of
* taking the GetFeatureInfo request parameters such as query_layers, bbox, x,
* y, etc., create the gt2 query objects for each featuretype and executing
* it. This process leads to a set of FeatureResults objects and its metadata,
* wich will be given to the <code>execute(FeatureTypeInfo[] ,
* FeatureResults[])</code> method, that a subclass should implement as a
* matter of setting up any resource/state it needs to later encoding.
* </p>
*
* <p>
* So, it should be enough to a subclass to implement the following methods in
* order to produce the requested output format:
*
* <ul>
* <li>
* execute(FeatureTypeInfo[], FeatureResults[], int, int)
* </li>
* <li>
* canProduce(String mapFormat)
* </li>
* <li>
* getSupportedFormats()
* </li>
* <li>
* writeTo(OutputStream)
* </li>
* </ul>
* </p>
*
* @author Gabriel Roldan, Axios Engineering
* @author Chris Holmes
* @version $Id: GetFeatureInfoDelegate.java,v 1.1 2004/07/15 21:13:14 jmacgill Exp $
*/
public abstract class GetFeatureInfoDelegate implements Response {
    /** DOCUMENT ME!  */
    private GetFeatureInfoRequest request;

    /**
     * Creates a new GetMapDelegate object.
     */
    public GetFeatureInfoDelegate() {
    }

    /**
     * Executes a Request, which must be a GetMapRequest.  Any other will cause
     * a class cast exception.
     *
     * @param request A valid GetMapRequest.
     *
     * @throws ServiceException If the request can not be executed.
     */
    public void execute(Request request) throws ServiceException {
        execute((GetFeatureInfoRequest) request);
    }

    /**
     * Executes a GetFeatureInfo request.  Builds the proper objects from the
     * request names.
     *
     * @param request A valid GetMapRequest.
     *
     * @throws WmsException If anything goes wrong.
     */
    protected void execute(GetFeatureInfoRequest request)
        throws WmsException {
        this.request = request;

        //use the layer of the QUERY_LAYERS parameter, not the LAYERS one
        FeatureTypeInfo[] layers = request.getQueryLayers();

        Query[] queries = buildQueries(layers);
        int x = request.getXPixel();
        int y = request.getYPixel();

        execute(layers, queries, x, y);
    }

    /**
     * DOCUMENT ME!
     *
     * @param gs DOCUMENT ME!
     */
    public void abort(Service gs) {
    }

    /**
     * Execute method for concrete children to implement.  Each param is an
     * array in the order things should be processed.
     *
     * @param requestedLayers Array of config information of the FeatureTypes
     *        to be processed.
     * @param queries Matching array of queries from the queries of the
     *        requested layers, already setted up with the bbox filter from
     *        the BBOX parameter of the GetMap request and to retrieve the
     *        specified attributes in the ATTRIBUTES request parameter.
     * @param x the X coordinate in pixels where the identification must be
     *        done relative to the image dimensions
     * @param y the Y coordinate in pixels where the identification must be
     *        done relative to the image dimensions
     *
     * @throws WmsException For any problems executing.
     */
    protected abstract void execute(FeatureTypeInfo[] requestedLayers,
        Query[] queries, int x, int y) throws WmsException;

    /**
     * Creates the array of queries to be executed for the request.
     *
     * <p>
     * Each query is setted up to retrieve the features that matches the BBOX
     * specified in the GetMap request
     * </p>
     *
     * @param layers The layers to request against.
     *
     * @return An array of queries, matching the arrays passed in.
     *
     * @throws WmsException If the custom filter can't be constructed.
     */
    private Query[] buildQueries(FeatureTypeInfo[] layers)
        throws WmsException {
        int nLayers = layers.length;
        Query[] queries = new Query[nLayers];
        GetFeatureInfoRequest infoRequest = getRequest();
        Envelope requestExtent = infoRequest.getGetMapRequest().getBbox();
        FilterFactory ffactory = FilterFactory.createFilterFactory();

        try {
            Filter finalLayerFilter;
            Query layerQuery;

            for (int i = 0; i < nLayers; i++) {
                FeatureType schema = layers[i].getFeatureType();

                finalLayerFilter = buildFilter(requestExtent, ffactory, schema);

                String[] props = guessProperties(layers[i], finalLayerFilter);
                layerQuery = new DefaultQuery(schema.getTypeName(),
                        finalLayerFilter, props);
                queries[i] = layerQuery;
            }
        } catch (IllegalFilterException ex) {
            throw new WmsException(ex,
                "Can't build layer queries: " + ex.getMessage(),
                getClass().getName() + "::parseFilters");
        } catch (java.io.IOException e) {
            throw new WmsException(e);
        }

        return queries;
    }

    /**
     * Builds the filter for a layer containing the BBOX filter defined by the
     * extent queries (BBOX param).
     *
     * @param requestExtent The extent to filter out.
     * @param ffactory A filterFactory to create new filters.
     * @param schema The FeatureTypeInfo of the request of this filter.
     *
     * @return A custom filter of the bbox and any optional custom filters.
     *
     * @throws IllegalFilterException For problems making the filter.
     */
    private Filter buildFilter(Envelope requestExtent, FilterFactory ffactory,
        FeatureType schema) throws IllegalFilterException {
        GeometryFilter bboxFilter;
        bboxFilter = ffactory.createGeometryFilter(AbstractFilter.GEOMETRY_INTERSECTS);

        BBoxExpression bboxExpr = ffactory.createBBoxExpression(requestExtent);
        Expression geomAttExpr = ffactory.createAttributeExpression(schema,
                schema.getDefaultGeometry().getName());
        bboxFilter.addLeftGeometry(geomAttExpr);
        bboxFilter.addRightGeometry(bboxExpr);

        return bboxFilter;
    }

    /**
     * Tries to guesss exactly wich property names are needed to query for a
     * given FeatureTypeInfo and the Filter that will be applied to it. By
     * this way, only the needed propertied will be queried to the underlying
     * FeatureSource in the hope that it will speed up the query
     *
     * <p>
     * Note that just the attributes exposed by the FeatureTypeInfo will be
     * taken in count. a FeatureTypeInfo exposes all it's attributes except if
     * the subset of desiref exposed attributes are specified in the catalog
     * configuration.
     * </p>
     *
     * <p>
     * This method guarantiees that at lest the default geometry attribute of
     * <code>layer</code> will be returned.
     * </p>
     *
     * @param layer The layer to process.
     * @param filter The filter to process with.
     *
     * @return An array of the propertyNames needed.
     *
     * @throws java.io.IOException DOCUMENT ME!
     *
     * @task TODO: by now just returns the geometry att. Implement the rest of
     *       the method to find the rest of attributes needed by inspecting
     *       the filter (would be enough to get all the
     *       AttributeExpression's?). I think that the style should be taken
     *       in count too.
     */
    private String[] guessProperties(FeatureTypeInfo layer, Filter filter)
        throws java.io.IOException {
        FeatureType type = layer.getFeatureType();
        List atts = new ArrayList();
        String geom_name = type.getDefaultGeometry().getName();

        if (!atts.contains(geom_name)) {
            atts.add(geom_name);
        }

        String[] properties = (String[]) atts.toArray(new String[atts.size()]);

        return properties;
    }

    /**
     * Gets the map request.  Used by delegate children to find out more
     * information about the request.
     *
     * @return The request to be processed.
     */
    protected GetFeatureInfoRequest getRequest() {
        return this.request;
    }

    /**
     * Evaluates if this GetFeatureInfo producer can generate the map format
     * specified by <code>mapFormat</code>, where <code>mapFormat</code> is
     * the MIME type of the requested response.
     *
     * @param mapFormat the MIME type of the output map format requiered
     *
     * @return true if class can produce a map in the passed format
     */
    public boolean canProduce(String mapFormat) {
        return getSupportedFormats().contains(mapFormat);
    }

    /**
     * Gets A list of the formats this delegate supports.
     *
     * @return A list of strings of the formats supported.
     */
    public abstract List getSupportedFormats();
}
TOP

Related Classes of org.vfny.geoserver.wms.responses.featureInfo.GetFeatureInfoDelegate

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.