/**
* Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* • Apache License, version 2.0
* • Apache Software License, version 1.0
* • GNU Lesser General Public License, version 3
* • Mozilla Public License, versions 1.0, 1.1 and 2.0
* • Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* License version 2 and the aforementioned licenses.
*
* As an exception to the terms of the GPL, you may copy, modify,
* propagate, and distribute a work formed by combining 52°North WPS
* GeoTools Modules with the Eclipse Libraries, or a work derivative of
* such a combination, even if such copying, modification, propagation, or
* distribution would otherwise violate the terms of the GPL. Nothing in
* this exception exempts you from complying with the GPL in all respects
* for all of the code used other than the Eclipse Libraries. You may
* include this exception and its grant of permissions when you distribute
* 52°North WPS GeoTools Modules. Inclusion of this notice with such a
* distribution constitutes a grant of such permissions. If you do not wish
* to grant these permissions, remove this paragraph from your
* distribution. "52°North WPS GeoTools Modules" means the 52°North WPS
* modules using GeoTools functionality - software licensed under version 2
* or any later version of the GPL, or a work based on such software and
* licensed under the GPL. "Eclipse Libraries" means Eclipse Modeling
* Framework Project and XML Schema Definition software distributed by the
* Eclipse Foundation and licensed under the Eclipse Public License Version
* 1.0 ("EPL"), or a work based on such software and licensed under the EPL.
*
* This program 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 General
* Public License for more details.
*/
package org.n52.wps.io;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.net.URLDecoder;
import java.util.Collection;
import javax.xml.namespace.QName;
import org.geotools.feature.NameImpl;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.gml2.SrsSyntax;
import org.geotools.referencing.CRS;
import org.n52.wps.commons.WPSConfig;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
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.feature.type.PropertyDescriptor;
import org.opengis.geometry.aggregate.MultiCurve;
import org.opengis.geometry.aggregate.MultiSurface;
import org.opengis.geometry.primitive.Curve;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.MultiPoint;
import com.vividsolutions.jts.geom.MultiPolygon;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
public class GTHelper {
private static Logger LOGGER = LoggerFactory.getLogger(GTHelper.class);
public static SimpleFeatureType createFeatureType(Collection<Property> attributes, Geometry newGeometry, String uuid, CoordinateReferenceSystem coordinateReferenceSystem){
String namespace = "http://www.52north.org/"+uuid;
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
if(coordinateReferenceSystem==null){
coordinateReferenceSystem= getDefaultCRS();
}
typeBuilder.setCRS(coordinateReferenceSystem);
typeBuilder.setNamespaceURI(namespace);
Name nameType = new NameImpl(namespace, "Feature-"+uuid);
typeBuilder.setName(nameType);
for(Property property : attributes){
if(property.getValue()!=null){
String name = property.getName().getLocalPart();
Class<?> binding = property.getType().getBinding();
if(binding.equals(Envelope.class)){
continue;
}
if(
(binding.equals(Geometry.class) ||
binding.equals(GeometryCollection.class) ||
binding.equals(MultiCurve.class) ||
binding.equals(MultiLineString.class) ||
binding.equals(Curve.class) ||
binding.equals(MultiPoint.class) ||
binding.equals(MultiPolygon.class) ||
binding.equals(MultiSurface.class) ||
binding.equals(LineString.class) ||
binding.equals(Point.class) ||
binding.equals(LineString.class) ||
binding.equals(Polygon.class))
&&!name.equals("location")){
if(newGeometry.getClass().equals(Point.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiPoint.class);
}else if(newGeometry.getClass().equals(LineString.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiLineString.class);
}else if( newGeometry.getClass().equals(Polygon.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiPolygon.class);
}else if(!binding.equals(Object.class)){
typeBuilder.add("GEOMETRY", newGeometry.getClass());
}
}else{
if(!name.equals("location") && binding.equals(Object.class)){
try{
Geometry g = (Geometry)property.getValue();
if(g.getClass().equals(Point.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiPoint.class);
}else if(g.getClass().equals(LineString.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiLineString.class);
}else if( g.getClass().equals(Polygon.class) && (!name.equals("location"))){
typeBuilder.add("GEOMETRY", MultiPolygon.class);
}else{
typeBuilder.add("GEOMETRY", g.getClass());
}
}catch(ClassCastException e){
}
}else if(!name.equals("location")){
typeBuilder.add(name, binding);
}
}
}
}
SimpleFeatureType featureType;
featureType = typeBuilder.buildFeatureType();
return featureType;
}
public static SimpleFeatureType createFeatureType(Geometry newGeometry, String uuid, CoordinateReferenceSystem coordinateReferenceSystem){
String namespace = "http://www.52north.org/"+uuid;
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
if(coordinateReferenceSystem==null){
coordinateReferenceSystem= getDefaultCRS();
}
typeBuilder.setCRS(coordinateReferenceSystem);
typeBuilder.setNamespaceURI(namespace);
Name nameType = new NameImpl(namespace, "Feature-"+uuid);
typeBuilder.setName(nameType);
typeBuilder.add("GEOMETRY", newGeometry.getClass());
SimpleFeatureType featureType;
featureType = typeBuilder.buildFeatureType();
return featureType;
}
public static SimpleFeature createFeature(String id, Geometry geometry, SimpleFeatureType featureType, Collection<Property> originalAttributes) {
if(geometry==null || geometry.isEmpty()){
return null;
}
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
SimpleFeature feature = null;
Collection<PropertyDescriptor> featureTypeAttributes = featureType.getDescriptors();
Object[] newData = new Object[featureType.getDescriptors().size()];
int i = 0;
for(PropertyDescriptor propertyDescriptor : featureTypeAttributes){
for(Property originalProperty : originalAttributes){
if(propertyDescriptor.getName().getLocalPart().equals(originalProperty.getName().getLocalPart())){
if(propertyDescriptor instanceof GeometryDescriptor){
newData[i] = geometry;
}else{
newData[i] = originalProperty.getValue();
}
}
}
if(propertyDescriptor instanceof GeometryDescriptor){
if(geometry.getGeometryType().equals("Point")){
Point[] points = new Point[1];
points[0] = (Point)geometry;
newData[i] = geometry.getFactory().createMultiPoint(points);
}else
if(geometry.getGeometryType().equals("LineString")){
LineString[] lineString = new LineString[1];
lineString[0] = (LineString)geometry;
newData[i] = geometry.getFactory().createMultiLineString(lineString);
}else
if(geometry.getGeometryType().equals("Polygon")){
Polygon[] polygons = new Polygon[1];
polygons[0] = (Polygon)geometry;
newData[i] = geometry.getFactory().createMultiPolygon(polygons);
}else{
newData[i] = geometry;
}
}
i++;
}
feature = featureBuilder.buildFeature(id, newData);
return feature;
}
public static Feature createFeature(String id, Geometry geometry, SimpleFeatureType featureType) {
if(geometry==null || geometry.isEmpty()){
return null;
}
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(featureType);
SimpleFeature feature = null;
Object[] newData = new Object[featureType.getDescriptors().size()];
int i = 0;
if(geometry.getGeometryType().equals("Point")){
Point[] points = new Point[1];
points[0] = (Point)geometry;
newData[i] = geometry.getFactory().createMultiPoint(points);
}else
if(geometry.getGeometryType().equals("LineString")){
LineString[] lineString = new LineString[1];
lineString[0] = (LineString)geometry;
newData[i] = geometry.getFactory().createMultiLineString(lineString);
}else
if(geometry.getGeometryType().equals("Polygon")){
Polygon[] polygons = new Polygon[1];
polygons[0] = (Polygon)geometry;
newData[i] = geometry.getFactory().createMultiPolygon(polygons);
}else{
newData[i] = geometry;
}
feature = featureBuilder.buildFeature(id, newData);
return feature;
}
public static QName createGML3SchemaForFeatureType(SimpleFeatureType featureType){
String uuid = featureType.getName().getNamespaceURI().replace("http://www.52north.org/", "");
String namespace = "http://www.52north.org/"+uuid;
String schema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xs:schema targetNamespace=\""+namespace+"\" " +
"xmlns:n52=\""+namespace+"\" "+
"xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "+
"xmlns:gml=\"http://www.opengis.net/gml\" "+
"elementFormDefault=\"qualified\" "+
"version=\"1.0\"> "+
"<xs:import namespace=\"http://www.opengis.net/gml\" "+
"schemaLocation=\"http://schemas.opengis.net/gml/3.1.1/base/gml.xsd\"/> ";
String typeName = featureType.getGeometryDescriptor().getType().getBinding().getName();
String geometryTypeName = "";
if(typeName.contains("Point")){
geometryTypeName = "PointPropertyType";
}
if(typeName.contains("MultiPoint")){
geometryTypeName = "MultiPointPropertyType";
}
if(typeName.contains("LineString")){
geometryTypeName = "CurvePropertyType";
}
if(typeName.contains("MultiLineString")){
geometryTypeName = "MultiCurvePropertyType";
}
if(typeName.contains("Polygon")){
geometryTypeName = "SurfacePropertyType";
}
if(typeName.contains("MultiPolygon")){
geometryTypeName = "MultiSurfacePropertyType";
}
// add feature type definition and generic geometry
schema = schema + "<xs:element name=\"Feature-"+uuid+"\" type=\"n52:FeatureType\" substitutionGroup=\"gml:_Feature\"/> " +
"<xs:complexType name=\"FeatureType\"> " +
"<xs:complexContent> " +
"<xs:extension base=\"gml:AbstractFeatureType\"> "+
"<xs:sequence> " +
//"<xs:element name=\"GEOMETRY\" type=\"gml:GeometryPropertyType\"> "+
"<xs:element name=\"GEOMETRY\" type=\"gml:"+geometryTypeName+"\"> "+
"</xs:element> ";
//add attributes
Collection<PropertyDescriptor> attributes = featureType.getDescriptors();
for(PropertyDescriptor property : attributes){
String attributeName = property.getName().getLocalPart();
if(!(property instanceof GeometryDescriptor)){
if(property.getType().getBinding().equals(String.class) ){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:string\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}else if(property.getType().getBinding().equals(Integer.class)|| property.getType().getBinding().equals(BigInteger.class)){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:integer\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}else if(property.getType().getBinding().equals(Double.class)){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:double\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}
}
}
//close
schema = schema + "</xs:sequence> "+
"</xs:extension> "+
"</xs:complexContent> "+
"</xs:complexType> "+
"</xs:schema>";
String schemalocation = "";
try {
schemalocation = storeSchema(schema, uuid);
} catch (IOException e) {
LOGGER.error("Exception while storing schema.", e);
throw new RuntimeException("Exception while storing schema.", e);
}
return new QName(namespace, schemalocation);
}
public static QName createGML2SchemaForFeatureType(SimpleFeatureType featureType){
String uuid = featureType.getName().getNamespaceURI().replace("http://www.52north.org/", "");
String namespace = "http://www.52north.org/"+uuid;
String schema = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><xs:schema targetNamespace=\""+namespace+"\" " +
"xmlns:n52=\""+namespace+"\" "+
"xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "+
"xmlns:gml=\"http://www.opengis.net/gml\" "+
"elementFormDefault=\"qualified\" "+
"version=\"1.0\"> "+
"<xs:import namespace=\"http://www.opengis.net/gml\" "+
"schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/> ";
// add feature type definition and generic geometry
schema = schema + "<xs:element name=\"Feature\" type=\"n52:FeatureType\" substitutionGroup=\"gml:_Feature\"/> " +
"<xs:complexType name=\"FeatureType\"> " +
"<xs:complexContent> " +
"<xs:extension base=\"gml:AbstractFeatureType\"> "+
"<xs:sequence> " +
"<xs:element name=\"GEOMETRY\" type=\"gml:GeometryPropertyType\"> "+
"</xs:element> ";
//add attributes
Collection<PropertyDescriptor> attributes = featureType.getDescriptors();
for(PropertyDescriptor property : attributes){
String attributeName = property.getName().getLocalPart();
if(!(property instanceof GeometryDescriptor)){
if(property.getType().getBinding().equals(String.class) ){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:string\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}else if(property.getType().getBinding().equals(Integer.class)|| property.getType().getBinding().equals(BigInteger.class)){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:integer\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}else if(property.getType().getBinding().equals(Double.class)){
schema = schema + "<xs:element name=\""+attributeName+"\" minOccurs=\"0\" maxOccurs=\"1\"> "+
"<xs:simpleType> ";
schema = schema + "<xs:restriction base=\"xs:double\"> "+
"</xs:restriction> "+
"</xs:simpleType> "+
"</xs:element> ";
}
}
}
//close
schema = schema + "</xs:sequence> "+
"</xs:extension> "+
"</xs:complexContent> "+
"</xs:complexType> "+
"</xs:schema>";
String schemalocation = "";
try {
schemalocation = storeSchema(schema, uuid);
} catch (IOException e) {
LOGGER.error("Exception while storing schema.", e);
throw new RuntimeException("Exception while storing schema.", e);
}
return new QName(namespace, schemalocation);
}
public static String storeSchema(String schema, String uuid) throws IOException {
String domain = WPSConfig.class.getProtectionDomain().getCodeSource().getLocation().getFile();
domain = URLDecoder.decode(domain, "UTF-8");
int startIndex = domain.indexOf("WEB-INF");
if(startIndex<0){
//not running as webapp
File f = File.createTempFile(uuid, ".xsd");
f.deleteOnExit();
FileWriter writer = new FileWriter(f);
writer.write(schema);
writer.flush();
writer.close();
return "file:"+f.getAbsolutePath();
}else{
domain = domain.substring(0,startIndex);
String baseDirLocation = domain;
String baseDir = baseDirLocation + "schemas" + File.separator;
File folder = new File(baseDir);
if(!folder.exists()){
folder.mkdirs();
}
File f = new File(baseDir+uuid+".xsd");
FileWriter writer = new FileWriter(f);
writer.write(schema);
writer.flush();
writer.close();
String url = WPSConfig.getServerBaseURL()+"/schemas/"+ uuid+".xsd";
return url;
}
}
private static CoordinateReferenceSystem getDefaultCRS(){
try {
return CRS.decode("EPSG:4326");
} catch (Exception e) {
LOGGER.error("Exception while decoding CRS EPSG:4326", e);
}
return null;
}
public static SrsSyntax getSrsSyntaxFromString(String syntaxString){
return SrsSyntax.valueOf(syntaxString);
}
}