configure application/wfs output

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

configure application/wfs output

sammeek
Hi Benjamin,

I have a process that stores outputs in a Geoserver WFS and I would like to configure some elements of the output, specifically the layer identifier. Additionally, I need to do this dynamically as part of the process, is there a simple way to do this in in the wps_config_geotools.xml or can this functionality be defined in the process that does the uploaded?

Thanks

Sam
Reply | Threaded
Open this post in threaded view
|

Re: configure application/wfs output

BenjaminPross
Hello Sam,

That is not a trivial task, as the layer name is defined by the file name of the shapefile, which is by default an UUID.
There is a workaround, however.
First, you will need to set GenericFileDataWithGTBinding as the data type of your output.
Then, you will have to create a file out of the FeatureCollection by yourself, by using the method below, e.g.:

try {
        this.result = new GenericFileDataWithGT(getShpFile(result, "layerName.shp"), "application/x-zipped-shp");
} catch (IllegalAttributeException | IOException e) {
        LOGGER.error(e.getMessage());
}
This example shows an AbstractAnnotatedAlgorithm, for the other algorithm types, you will need something like this:

HashMap<String, IData> result = new HashMap<String, IData>();

result.put("RESULT",
                new GenericFileDataWithGTBinding(new GenericFileDataWithGT(getShpFile(result, "layerName.shp"), "application/x-zipped-shp")));
return result;

Then you will need to modify the GeoserverWFSGenerator. Use either the attached class or library.

Hope this helps.

Cheers,

Benjamin


        public static File getShpFile(FeatureCollection<?, ?> collection, String filename)
                        throws IOException, IllegalAttributeException {
                SimpleFeatureType type = null;
                SimpleFeatureBuilder build = null;
                FeatureIterator<?> iterator = collection.features();
                List<SimpleFeature> featureList = new ArrayList<>();
                ListFeatureCollection modifiedFeatureCollection = null;
                Transaction transaction = new DefaultTransaction("create");
                FeatureStore<SimpleFeatureType, SimpleFeature> store = null;
                File shp = new File(System.getProperty("java.io.tmpdir") + File.separator + filename);
                while (iterator.hasNext()) {
                        SimpleFeature sf = (SimpleFeature) iterator.next();
                        // create SimpleFeatureType
                        if (type == null) {
                                SimpleFeatureType inType = (SimpleFeatureType) collection
                                                .getSchema();
                                SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
                                builder.setName(inType.getName());
                                builder.setNamespaceURI(inType.getName().getNamespaceURI());

                                if (collection.getSchema().getCoordinateReferenceSystem() == null) {
                                        builder.setCRS(DefaultGeographicCRS.WGS84);
                                } else {
                                        builder.setCRS(collection.getSchema()
                                                        .getCoordinateReferenceSystem());
                                }

                                builder.setDefaultGeometry(sf.getDefaultGeometryProperty()
                                                .getName().getLocalPart());

                                /*
                                 * seems like the geometries must always be the first property..
                                 * @see also ShapeFileDataStore.java getSchema() method
                                 */
                                Property geomProperty = sf.getDefaultGeometryProperty();

                                if(geomProperty.getType().getBinding().getSimpleName().equals("Geometry")){
                                Geometry g = (Geometry)geomProperty.getValue();
                                if(g!=null){
                                        GeometryAttribute geo = null;
                                        if(g instanceof MultiPolygon){

                                        GeometryAttribute oldGeometryDescriptor = sf.getDefaultGeometryProperty();
                                        GeometryType type1 = new GeometryTypeImpl(geomProperty.getName(),MultiPolygon.class, oldGeometryDescriptor.getType().getCoordinateReferenceSystem(),oldGeometryDescriptor.getType().isIdentified(),oldGeometryDescriptor.getType().isAbstract(),oldGeometryDescriptor.getType().getRestrictions(),oldGeometryDescriptor.getType().getSuper(),oldGeometryDescriptor.getType().getDescription());

                                        GeometryDescriptor newGeometryDescriptor = new GeometryDescriptorImpl(type1,geomProperty.getName(),0,1,true,null);
                                        Identifier identifier = new GmlObjectIdImpl(sf.getID());
                                        geo = new GeometryAttributeImpl((Object)g,newGeometryDescriptor, identifier);
                                        sf.setDefaultGeometryProperty(geo);
                                        sf.setDefaultGeometry(g);
                                        }
                                        if(geo != null){
                                        builder.add(geo.getName().getLocalPart(), geo
                                                        .getType().getBinding());
                                        }
                                }
                                }else if (isSupportedShapefileType(geomProperty.getType())
                                                && (geomProperty.getValue() != null)) {
                                        builder.add(geomProperty.getName().getLocalPart(), geomProperty
                                                        .getType().getBinding());
                                }

                                for (Property prop : sf.getProperties()) {

                                        if (prop.getType() instanceof GeometryType) {
                                                /*
                                                 * skip, was handled before
                                                 */
                                        }else if (isSupportedShapefileType(prop.getType())
                                                        && (prop.getValue() != null)) {
                                                builder.add(prop.getName().getLocalPart(), prop
                                                                .getType().getBinding());
                                        }
                                }

                                type = builder.buildFeatureType();

                                ShapefileDataStore dataStore = new ShapefileDataStore(shp
                                                .toURI().toURL());
                                dataStore.createSchema(type);
                                dataStore.forceSchemaCRS(type.getCoordinateReferenceSystem());

                                String typeName = dataStore.getTypeNames()[0];
                                store = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore
                                                .getFeatureSource(typeName);

                                store.setTransaction(transaction);

                                build = new SimpleFeatureBuilder(type);
                                modifiedFeatureCollection = new ListFeatureCollection(type);
                        }
                        for (AttributeType attributeType : type.getTypes()) {
                                build.add(sf.getProperty(attributeType.getName()).getValue());
                        }

                        SimpleFeature newSf = build.buildFeature(sf.getIdentifier()
                                        .getID());

                        featureList.add(newSf);
                }

                try {
                        modifiedFeatureCollection.addAll(featureList);
                        store.addFeatures(modifiedFeatureCollection);
                        transaction.commit();
                        return shp;
                } catch (Exception e1) {
                        e1.printStackTrace();
                        transaction.rollback();
                        throw new IOException(e1.getMessage());
                } finally {
                        transaction.close();
                }
        }

        private static boolean isSupportedShapefileType(PropertyType type) {
                String supported[] = { "String", "Integer", "Double", "Boolean",
                                "Date", "LineString", "MultiLineString", "Polygon",
                                "MultiPolygon", "Point", "MultiPoint", "Long"};
                for (String iter : supported) {
                        if (type.getBinding().getSimpleName().equalsIgnoreCase(iter)) {
                                return true;
                        }
                }
                return false;
        }
Reply | Threaded
Open this post in threaded view
|

Re: configure application/wfs output

sammeek
Hi Benjamin,

This works a treat, thank you very much.

I also want to define the workspace and store in the request. Is this done in this line of the WFS Generator?

                Document doc = createXML("N52:"+file.getName().subSequence(0, file.getName().length()-4), capabilitiesLink);

I ask because I tried changing it but with no joy!

Thanks

Sam
Reply | Threaded
Open this post in threaded view
|

Re: configure application/wfs output

Daniel
In reply to this post by BenjaminPross
Am 06/02/2015 um 14:25 schrieb BenjaminPross:
> Hello Sam,
>
> That is not a trivial task, as the layer name is defined by the file name of
> the shapefile, which is by default an UUID.
> There is a workaround, however.

Is this so common a use case that we should try to refactor the layer
name creation? For example, we could change it to a factory pattern so
that the generator can be switched out more easily without actually
changing the GeoserverWFSGenerator.java ?

Seems to me this is worth a GitHub issue with a feature request.

/Daniel

> First, you will need to set GenericFileDataWithGTBinding as the data type of
> your output.
> Then, you will have to create a file out of the FeatureCollection by
> yourself, by using the method below, e.g.:
>
> try {
> this.result = new GenericFileDataWithGT(getShpFile(result,
> "layerName.shp"), "application/x-zipped-shp");
> } catch (IllegalAttributeException | IOException e) {
> LOGGER.error(e.getMessage());
> }
> This example shows an AbstractAnnotatedAlgorithm, for the other algorithm
> types, you will need something like this:
>
> HashMap<String, IData> result = new HashMap<String, IData>();
>
> result.put("RESULT",
> new GenericFileDataWithGTBinding(new
> GenericFileDataWithGT(getShpFile(result, "layerName.shp"),
> "application/x-zipped-shp")));
> return result;
>
> Then you will need to modify the GeoserverWFSGenerator. Use either the
> attached class
> <http://geoprocessing.forum.52north.org/file/n4026001/GeoserverWFSGenerator.java>
> or  library
> <http://geoprocessing.forum.52north.org/file/n4026001/52n-wps-io-geotools-3.jar>
> .
>
> Hope this helps.
>
> Cheers,
>
> Benjamin
>
>
> public static File getShpFile(FeatureCollection<?, ?> collection, String
> filename)
> throws IOException, IllegalAttributeException {
> SimpleFeatureType type = null;
> SimpleFeatureBuilder build = null;
> FeatureIterator<?> iterator = collection.features();
> List<SimpleFeature> featureList = new ArrayList<>();
> ListFeatureCollection modifiedFeatureCollection = null;
> Transaction transaction = new DefaultTransaction("create");
> FeatureStore<SimpleFeatureType, SimpleFeature> store = null;
> File shp = new File(System.getProperty("java.io.tmpdir") + File.separator
> + filename);
> while (iterator.hasNext()) {
> SimpleFeature sf = (SimpleFeature) iterator.next();
> // create SimpleFeatureType
> if (type == null) {
> SimpleFeatureType inType = (SimpleFeatureType) collection
> .getSchema();
> SimpleFeatureTypeBuilder builder = new SimpleFeatureTypeBuilder();
> builder.setName(inType.getName());
> builder.setNamespaceURI(inType.getName().getNamespaceURI());
>
> if (collection.getSchema().getCoordinateReferenceSystem() == null) {
> builder.setCRS(DefaultGeographicCRS.WGS84);
> } else {
> builder.setCRS(collection.getSchema()
> .getCoordinateReferenceSystem());
> }
>
> builder.setDefaultGeometry(sf.getDefaultGeometryProperty()
> .getName().getLocalPart());
>
> /*
> * seems like the geometries must always be the first property..
> * @see also ShapeFileDataStore.java getSchema() method
> */
> Property geomProperty = sf.getDefaultGeometryProperty();
>
>
> if(geomProperty.getType().getBinding().getSimpleName().equals("Geometry")){
> Geometry g = (Geometry)geomProperty.getValue();
> if(g!=null){
> GeometryAttribute geo = null;
> if(g instanceof MultiPolygon){
>
> GeometryAttribute oldGeometryDescriptor =
> sf.getDefaultGeometryProperty();
> GeometryType type1 = new
> GeometryTypeImpl(geomProperty.getName(),MultiPolygon.class,
> oldGeometryDescriptor.getType().getCoordinateReferenceSystem(),oldGeometryDescriptor.getType().isIdentified(),oldGeometryDescriptor.getType().isAbstract(),oldGeometryDescriptor.getType().getRestrictions(),oldGeometryDescriptor.getType().getSuper(),oldGeometryDescriptor.getType().getDescription());
>
> GeometryDescriptor newGeometryDescriptor = new
> GeometryDescriptorImpl(type1,geomProperty.getName(),0,1,true,null);
> Identifier identifier = new GmlObjectIdImpl(sf.getID());
> geo = new GeometryAttributeImpl((Object)g,newGeometryDescriptor,
> identifier);
> sf.setDefaultGeometryProperty(geo);
> sf.setDefaultGeometry(g);
> }
> if(geo != null){
> builder.add(geo.getName().getLocalPart(), geo
> .getType().getBinding());
> }
> }
> }else if (isSupportedShapefileType(geomProperty.getType())
> && (geomProperty.getValue() != null)) {
> builder.add(geomProperty.getName().getLocalPart(), geomProperty
> .getType().getBinding());
> }
>
> for (Property prop : sf.getProperties()) {
>
> if (prop.getType() instanceof GeometryType) {
> /*
> * skip, was handled before
> */
> }else if (isSupportedShapefileType(prop.getType())
> && (prop.getValue() != null)) {
> builder.add(prop.getName().getLocalPart(), prop
> .getType().getBinding());
> }
> }
>
> type = builder.buildFeatureType();
>
> ShapefileDataStore dataStore = new ShapefileDataStore(shp
> .toURI().toURL());
> dataStore.createSchema(type);
> dataStore.forceSchemaCRS(type.getCoordinateReferenceSystem());
>
> String typeName = dataStore.getTypeNames()[0];
> store = (FeatureStore<SimpleFeatureType, SimpleFeature>) dataStore
> .getFeatureSource(typeName);
>
> store.setTransaction(transaction);
>
> build = new SimpleFeatureBuilder(type);
> modifiedFeatureCollection = new ListFeatureCollection(type);
> }
> for (AttributeType attributeType : type.getTypes()) {
> build.add(sf.getProperty(attributeType.getName()).getValue());
> }
>
> SimpleFeature newSf = build.buildFeature(sf.getIdentifier()
> .getID());
>
> featureList.add(newSf);
> }
>
> try {
> modifiedFeatureCollection.addAll(featureList);
> store.addFeatures(modifiedFeatureCollection);
> transaction.commit();
> return shp;
> } catch (Exception e1) {
> e1.printStackTrace();
> transaction.rollback();
> throw new IOException(e1.getMessage());
> } finally {
> transaction.close();
> }
> }
>
> private static boolean isSupportedShapefileType(PropertyType type) {
> String supported[] = { "String", "Integer", "Double", "Boolean",
> "Date", "LineString", "MultiLineString", "Polygon",
> "MultiPolygon", "Point", "MultiPoint", "Long"};
> for (String iter : supported) {
> if (type.getBinding().getSimpleName().equalsIgnoreCase(iter)) {
> return true;
> }
> }
> return false;
> }
>
>
>
> --
> View this message in context: http://geoprocessing.forum.52north.org/configure-application-wfs-output-tp4026000p4026001.html
> Sent from the 52° North - Geoprocessing Community Forum mailing list archive at Nabble.com.
> _______________________________________________
> Geoprocessingservices mailing list
> [hidden email]
> http://list.52north.org/mailman/listinfo/geoprocessingservices
> http://geoprocessing.forum.52north.org
> Please respect our mailing list guidelines:
> http://52north.org/resources/mailing-lists-and-forums/guidelines
>


--
Daniel Nüst
52°North Initiative for Geospatial Open Source Software GmbH
Martin-Luther-King-Weg 24
48155 Münster, Germany
E-Mail: [hidden email]
Fon: +49-(0)-251–396371-36
Fax: +49-(0)-251–396371-11

http://52north.org/
Twitter: @FiveTwoN

General Managers: Dr. Albert Remke, Dr. Andreas Wytzisk
Local Court Muenster HRB 10849
_______________________________________________
Geoprocessingservices mailing list
[hidden email]
http://list.52north.org/mailman/listinfo/geoprocessingservices
http://geoprocessing.forum.52north.org
Please respect our mailing list guidelines:
http://52north.org/resources/mailing-lists-and-forums/guidelines
Reply | Threaded
Open this post in threaded view
|

Re: configure application/wfs output

BenjaminPross
In reply to this post by sammeek
Hi Sam,

This is done in the GeoServerUploader, in the createWorkspace() method.
We should make this configurable in the future, I guess..

Cheers,

Benjamin

Am 31.03.2015 um 11:24 schrieb sammeek:

> Hi Benjamin,
>
> This works a treat, thank you very much.
>
> I also want to define the workspace and store in the request. Is this done
> in this line of the WFS Generator?
>
> Document doc = createXML("N52:"+file.getName().subSequence(0,
> file.getName().length()-4), capabilitiesLink);
>
> I ask because I tried changing it but with no joy!
>
> Thanks
>
> Sam
>
>
>
> --
> View this message in context: http://geoprocessing.forum.52north.org/configure-application-wfs-output-tp4026000p4026041.html
> Sent from the 52° North - Geoprocessing Community Forum mailing list archive at Nabble.com.
> _______________________________________________
> Geoprocessingservices mailing list
> [hidden email]
> http://list.52north.org/mailman/listinfo/geoprocessingservices
> http://geoprocessing.forum.52north.org
> Please respect our mailing list guidelines:
> http://52north.org/resources/mailing-lists-and-forums/guidelines


--
Benjamin Proß
Software Engineer
52°North Geoprocessing Community

52°North Initiative for Geospatial Open Source Software GmbH
Martin-Luther-King-Weg 24
Fon: +49-(0)-251–396371-42
Fax: +49-(0)-251–396371-11
[hidden email]
http://52north.org/

General Managers: Dr. Albert Remke, Dr. Andreas Wytzisk
Local Court Muenster HRB 10849

_______________________________________________
Geoprocessingservices mailing list
[hidden email]
http://list.52north.org/mailman/listinfo/geoprocessingservices
http://geoprocessing.forum.52north.org
Please respect our mailing list guidelines:
http://52north.org/resources/mailing-lists-and-forums/guidelines