Package org.geoserver.wps.gs

Source Code of org.geoserver.wps.gs.ImportProcess

/* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wps.gs;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.CatalogBuilder;
import org.geoserver.catalog.DataStoreInfo;
import org.geoserver.catalog.FeatureTypeInfo;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.ProjectionPolicy;
import org.geoserver.catalog.StyleInfo;
import org.geoserver.catalog.WorkspaceInfo;
import org.geoserver.wps.WPSException;
import org.geoserver.wps.jts.DescribeParameter;
import org.geoserver.wps.jts.DescribeProcess;
import org.geoserver.wps.jts.DescribeResult;
import org.geotools.data.DataStore;
import org.geotools.data.DataUtilities;
import org.geotools.data.DefaultTransaction;
import org.geotools.data.Transaction;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureStore;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.process.ProcessException;
import org.geotools.referencing.CRS;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

/**
* Imports a feature collection into the GeoServer catalog
*
* @author Andrea Aime - OpenGeo
*
*/
@DescribeProcess(title = "Catalog import", description = "Imports the provided feature collection into the catalog")
public class ImportProcess implements GeoServerProcess {

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

    private Catalog catalog;

    public ImportProcess(Catalog catalog) {
        this.catalog = catalog;
    }

    @DescribeResult(name = "layerName", description = "The qualified name of the created layer (workspace:name)")
    public String execute(
            @DescribeParameter(name = "features", description = "The features that will make up the new GeoServer layer") SimpleFeatureCollection features,
            @DescribeParameter(name = "workspace", min = 0, description = "The target workspace (the default one will be used if omitted)") String workspace,
            @DescribeParameter(name = "store", min = 0, description = "The target store (the workspace default one will be used if omitted)") String store,
            @DescribeParameter(name = "name", min = 0, description = "The name of the layer to be created (if missing the name of the features contained in the collection will be used") String name,
            @DescribeParameter(name = "srs", min = 0, description = "The target coordinate reference system (the feature collection one will be analyzed and used if possible)") CoordinateReferenceSystem srs,
            @DescribeParameter(name = "srsHandling", min = 0, description = "The desired SRS handling, FORCE_DECLARED will be used if not specified") ProjectionPolicy srsHandling,
            @DescribeParameter(name = "styleName", min = 0, description = "The name of the style to be used for the layer. If missing a default style will be chosen according to the type of geometries contained in the collection") String styleName)
            throws ProcessException {

        // first off, decide what is the target store
        WorkspaceInfo ws;
        if (workspace != null) {
            ws = catalog.getWorkspaceByName(workspace);
            if (ws == null) {
                throw new ProcessException("Could not find workspace " + workspace);
            }
        } else {
            ws = catalog.getDefaultWorkspace();
            if (ws == null) {
                throw new ProcessException(
                        "The catalog is empty, could not find a default workspace");
            }
        }

        // ok, find the target store
        DataStoreInfo storeInfo;
        if (store != null) {
            storeInfo = catalog.getDataStoreByName(ws.getName(), store);
            if (storeInfo == null) {
                throw new ProcessException("Could not find store " + store + " in workspace "
                        + workspace);
                // TODO: support store creation
            }
        } else {
            storeInfo = catalog.getDefaultDataStore(ws);
            if (storeInfo == null) {
                throw new ProcessException("Could not find a default store in workspace "
                        + ws.getName());
            }
        }

        // check if the target layer and the target feature type are not
        // already there (this is a half-assed attempt as we don't have
        // an API telling us how the feature type name will be changed
        // by DataStore.createSchema(...), but better than fully importing
        // the data into the target store to find out we cannot create the layer...)
        String tentativeTargetName = null;
        if (name != null) {
            tentativeTargetName = ws.getName() + ":" + name;
        } else {
            tentativeTargetName = ws.getName() + ":" + features.getSchema().getTypeName();
        }
        if (catalog.getLayer(tentativeTargetName) != null) {
            throw new ProcessException("Target layer " + tentativeTargetName + " already exists");
        }

        // check the target style if any
        StyleInfo targetStyle = null;
        if (styleName != null) {
            targetStyle = catalog.getStyleByName(styleName);
            if (targetStyle == null) {
                throw new ProcessException("Could not find style " + styleName);
            }
        }

        // check the target crs
        String targetSRSCode = null;
        if (srs != null) {
            try {
                Integer code = CRS.lookupEpsgCode(srs, true);
                if (code == null) {
                    throw new WPSException("Could not find a EPSG code for " + srs);
                }
                targetSRSCode = "EPSG:" + code;
            } catch (Exception e) {
                throw new ProcessException("Could not lookup the EPSG code for the provided srs", e);
            }
        } else {
            // check we can extract a code from the original data
            GeometryDescriptor gd = features.getSchema().getGeometryDescriptor();
            if (gd == null) {
                // data is geometryless, we need a fake SRS
                targetSRSCode = "EPSG:4326";
                srsHandling = ProjectionPolicy.FORCE_DECLARED;
            } else {
                CoordinateReferenceSystem nativeCrs = gd.getCoordinateReferenceSystem();
                if (nativeCrs == null) {
                    throw new ProcessException("The original data has no native CRS, "
                            + "you need to specify the srs parameter");
                } else {
                    try {
                        Integer code = CRS.lookupEpsgCode(nativeCrs, true);
                        if (code == null) {
                            throw new ProcessException("Could not find an EPSG code for data "
                                    + "native spatial reference system: " + nativeCrs);
                        } else {
                            targetSRSCode = "EPSG:" + code;
                        }
                    } catch (Exception e) {
                        throw new ProcessException("Failed to loookup an official EPSG code for "
                                + "the source data native " + "spatial reference system", e);
                    }
                }
            }
        }

        // import the data into the target store
        SimpleFeatureType targetType;
        try {
            targetType = importDataIntoStore(features, name, storeInfo);
        } catch (IOException e) {
            throw new ProcessException("Failed to import data into the target store", e);
        }

        // now import the newly created layer into GeoServer
        try {
            CatalogBuilder cb = new CatalogBuilder(catalog);
            cb.setStore(storeInfo);

            // build the typeInfo and set CRS if necessary
            FeatureTypeInfo typeInfo = cb.buildFeatureType(targetType.getName());
            if (targetSRSCode != null) {
                typeInfo.setSRS(targetSRSCode);
            }
            if (srsHandling != null) {
                typeInfo.setProjectionPolicy(srsHandling);
            }
            // compute the bounds
            cb.setupBounds(typeInfo);

            // build the layer and set a style
            LayerInfo layerInfo = cb.buildLayer(typeInfo);
            if (targetStyle != null) {
                layerInfo.setDefaultStyle(targetStyle);
            }

            catalog.add(typeInfo);
            catalog.add(layerInfo);

            return typeInfo.getPrefixedName();
        } catch (Exception e) {
            throw new ProcessException(
                    "Failed to complete the import inside the GeoServer catalog", e);
        }
    }

    private SimpleFeatureType importDataIntoStore(SimpleFeatureCollection features, String name,
            DataStoreInfo storeInfo) throws IOException, ProcessException {
        SimpleFeatureType targetType;
        // grab the data store
        DataStore ds = (DataStore) storeInfo.getDataStore(null);

        // decide on the target ft name
        SimpleFeatureType sourceType = features.getSchema();
        if (name != null) {
            SimpleFeatureTypeBuilder tb = new SimpleFeatureTypeBuilder();
            tb.init(sourceType);
            tb.setName(name);
            sourceType = tb.buildFeatureType();
        }

        // create the schema
        ds.createSchema(sourceType);

        // try to get the target feature type (might have slightly different
        // name and structure)
        targetType = ds.getSchema(sourceType.getTypeName());
        if (targetType == null) {
            // ouch, the name was changed... we can only guess now...
            // try with the typical Oracle mangling
            targetType = ds.getSchema(sourceType.getTypeName().toUpperCase());
        }

        if (targetType == null) {
            throw new WPSException(
                    "The target schema was created, but with a name "
                            + "that we cannot relate to the one we provided the data store. Cannot proceeed further");
        } else {
            // check the layer is not already there
            String newLayerName = storeInfo.getWorkspace().getName() + ":"
                    + targetType.getTypeName();
            LayerInfo layer = catalog.getLayerByName(newLayerName);
            // todo: we should not really reach here and know beforehand what the targetType
            // name is, but if we do we should at least get a way to drop it
            if (layer != null) {
                throw new ProcessException("Target layer " + newLayerName
                        + " already exists in the catalog");
            }
        }

        // try to establish a mapping with old and new attributes. This is again
        // just guesswork until we have a geotools api that will give us the
        // exact mapping to be performed
        Map<String, String> mapping = buildAttributeMapping(sourceType, targetType);

        // start a transaction and fill the target with the input features
        Transaction t = new DefaultTransaction();
        SimpleFeatureStore fstore = (SimpleFeatureStore) ds.getFeatureSource(targetType
                .getTypeName());
        fstore.setTransaction(t);
        SimpleFeatureIterator fi = features.features();
        SimpleFeatureBuilder fb = new SimpleFeatureBuilder(targetType);
        while (fi.hasNext()) {
            SimpleFeature source = fi.next();
            fb.reset();
            for (String sname : mapping.keySet()) {
                fb.set(mapping.get(sname), source.getAttribute(sname));
            }
            SimpleFeature target = fb.buildFeature(null);
            fstore.addFeatures(DataUtilities.collection(target));
        }
        t.commit();
        t.close();

        return targetType;
    }

    /**
     * Applies a set of heuristics to find which target attribute corresponds to a certain input
     * attribute
     *
     * @param sourceType
     * @param targetType
     * @return
     */
    Map<String, String> buildAttributeMapping(SimpleFeatureType sourceType,
            SimpleFeatureType targetType) {
        // look for the typical manglings. For example, if the target is a
        // shapefile store it will move the geometry and name it the_geom

        // collect the source names
        Set<String> sourceNames = new HashSet<String>();
        for (AttributeDescriptor sd : sourceType.getAttributeDescriptors()) {
            sourceNames.add(sd.getLocalName());
        }

        // first check if we have been kissed by sheer luck and the names are
        // the same
        Map<String, String> result = new HashMap<String, String>();
        for (String name : sourceNames) {
            if (targetType.getDescriptor(name) != null) {
                result.put(name, name);
            }
        }
        sourceNames.removeAll(result.keySet());

        // then check for simple case difference (Oracle case)
        for (String name : sourceNames) {
            for (AttributeDescriptor td : targetType.getAttributeDescriptors()) {
                if (td.getLocalName().equalsIgnoreCase(name)) {
                    result.put(name, td.getLocalName());
                    break;
                }
            }
        }
        sourceNames.removeAll(result.keySet());

        // then check attribute names being cut (another Oracle case)
        for (String name : sourceNames) {
            String loName = name.toLowerCase();
            for (AttributeDescriptor td : targetType.getAttributeDescriptors()) {
                String tdName = td.getLocalName().toLowerCase();
                if (loName.startsWith(tdName)) {
                    result.put(name, td.getLocalName());
                    break;
                }
            }
        }
        sourceNames.removeAll(result.keySet());

        // consider the shapefile geometry descriptor mangling
        if (targetType.getGeometryDescriptor() != null
                && "the_geom".equals(targetType.getGeometryDescriptor().getLocalName())
                && !"the_geom".equalsIgnoreCase(sourceType.getGeometryDescriptor().getLocalName())) {
            result.put(sourceType.getGeometryDescriptor().getLocalName(), "the_geom");
        }

        // and finally we return with as much as we can match
        if (!sourceNames.isEmpty()) {
            LOGGER.warning("Could not match the following attributes " + sourceNames
                    + " to the target feature type ones: " + targetType);
        }
        return result;
    }
}
TOP

Related Classes of org.geoserver.wps.gs.ImportProcess

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.