Package org.geotools.gml2.bindings

Source Code of org.geotools.gml2.bindings.GMLEncodingUtils

package org.geotools.gml2.bindings;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.eclipse.xsd.XSDComplexTypeDefinition;
import org.eclipse.xsd.XSDCompositor;
import org.eclipse.xsd.XSDDerivationMethod;
import org.eclipse.xsd.XSDElementDeclaration;
import org.eclipse.xsd.XSDFactory;
import org.eclipse.xsd.XSDModelGroup;
import org.eclipse.xsd.XSDParticle;
import org.eclipse.xsd.XSDTypeDefinition;
import org.eclipse.xsd.util.XSDConstants;
import org.geotools.feature.NameImpl;
import org.geotools.gml2.GMLConfiguration;
import org.geotools.util.logging.Logging;
import org.geotools.xlink.XLINK;
import org.geotools.xml.Configuration;
import org.geotools.xml.Encoder;
import org.geotools.xml.SchemaIndex;
import org.geotools.xml.Schemas;
import org.geotools.xml.XSD;
import org.geotools.xs.XS;
import org.opengis.feature.ComplexAttribute;
import org.opengis.feature.Feature;
import org.opengis.feature.GeometryAttribute;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.ComplexType;
import org.opengis.feature.type.FeatureType;
import org.opengis.feature.type.GeometryDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.geometry.BoundingBox;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.w3c.dom.Document;
import org.xml.sax.Attributes;

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;

/**
*
*
* @source $URL$
*/
public class GMLEncodingUtils {

    /** logging instance */
    static Logger LOGGER = Logging.getLogger( "org.geotools.gml");
   
    XSD gml;
   
    public GMLEncodingUtils(XSD gml) {
        this.gml = gml;
    }
   
    public List AbstractFeatureType_getProperties(Object object,
            XSDElementDeclaration element, SchemaIndex schemaIndex, Set<String> toFilter,
            Configuration configuration) {
       
        Feature feature = (Feature) object;
       
        //check if this was a resolved feature, if so dont return anything
        // TODO: this is just a hack for our lame xlink implementation
        if (feature.getUserData().get("xlink:id") != null) {
            return Collections.EMPTY_LIST;
        }

        FeatureType featureType = feature.getType();

        String namespace = featureType.getName().getNamespaceURI();

        if (namespace == null) {
            namespace = element.getTargetNamespace();
        }

        String typeName = featureType.getName().getLocalPart();
        QName qualifiedTypeName = new QName(namespace, typeName);

        //find the type in the schema
        XSDTypeDefinition type = schemaIndex.getTypeDefinition(qualifiedTypeName);

        if (type == null) {
            //type not found, do a check for an element, and use its type
            XSDElementDeclaration e = schemaIndex.getElementDeclaration(qualifiedTypeName);

            if (e != null) {
                type = e.getTypeDefinition();
            }
        }

        if (type == null) {
            if (featureType instanceof SimpleFeatureType) {
                // could not find the feature type in the schema, create a mock one
                LOGGER.fine("Could find type for " + typeName
                        + " in the schema, generating type from feature.");
                type = createXmlTypeFromFeatureType((SimpleFeatureType) featureType, schemaIndex,
                        toFilter);
            } else {
                // look for an element declaration smuggled in the UserData map.
                XSDElementDeclaration e = (XSDElementDeclaration) feature.getDescriptor()
                        .getUserData().get(XSDElementDeclaration.class);
                if (e != null) {
                    type = e.getTypeDefinition();
                } else {
                    throw new RuntimeException("Could not find type for " + qualifiedTypeName
                            + " in schema");
                }
            }
        }

        List particles = Schemas.getChildElementParticles(type, true);
        List properties = new ArrayList();

    O:  for (int i = 0; i < particles.size(); i++) {
            XSDParticle particle = (XSDParticle) particles.get(i);
            XSDElementDeclaration attribute = (XSDElementDeclaration) particle.getContent();

            if (attribute.isElementDeclarationReference()) {
                attribute = attribute.getResolvedElementDeclaration();
            }
           
            if (gml.qName("boundedBy")
                    .equals(new QName(attribute.getTargetNamespace(), attribute.getName()))) {
                BoundingBox bounds = getBoundedBy(feature, configuration);
                if (bounds != null) {
                    properties.add(new Object[] { particle, bounds });
                }
            } else if (featureType instanceof SimpleFeatureType) {
                // first simple feature hack, if the schema "overrides" gml attributes like
                // name and description, ignore the gml version
                boolean skip = false;
                if (gml.getNamespaceURI().equals(attribute.getTargetNamespace())) {
                    for (int j = i+1; j < particles.size(); j++) {
                        XSDParticle particle2 = (XSDParticle) particles.get(j);
                        XSDElementDeclaration attribute2 = (XSDElementDeclaration) particle2.getContent();
                        if (attribute2.isElementDeclarationReference()) {
                            attribute2 = attribute2.getResolvedElementDeclaration();
                        }
                        if (attribute2.getName().equals(attribute.getName())) {
                            skip = true;
                            break;
                        }
                    }
                }
                if (skip) {
                    continue;
                }
               
                // simple feature brain damage: discard namespace
                // make sure the feature type has an element
                if (!isValidDescriptor(featureType, new NameImpl(attribute.getName()))) {
                    continue;
                }
                // get the value
                Object attributeValue = ((SimpleFeature) feature).getAttribute(attribute.getName());
                if (attributeValue != null && attributeValue instanceof Geometry) {
                    Object obj = ((Geometry) attributeValue).getUserData();
                    Map<Object, Object> userData = new HashMap<Object, Object>();
                    if (obj != null && obj instanceof Map) {
                        userData.putAll((Map) obj);
                    }
                    userData.put(CoordinateReferenceSystem.class, featureType
                            .getCoordinateReferenceSystem());
                    ((Geometry) attributeValue).setUserData(userData);
                }
                properties.add(new Object[] { particle, attributeValue });
            } else {
                // namespaces matter for non-simple feature types
                Name propertyName = new NameImpl(attribute.getTargetNamespace(), attribute
                        .getName());
                // make sure the feature type has an element
                if (!isValidDescriptor(featureType, propertyName)) {
                    continue;
                }
                // get the value (might be multiple)
                for (Property property : feature.getProperties(propertyName)) {
                    Object value;
                    if (property instanceof ComplexAttribute) {
                        // do not unpack complex attributes as these may have their own bindings, which
                        // will be applied by the encoder
                        value = property;
                    } else if (property instanceof GeometryAttribute) {
                        value = property.getValue();
                        if (value != null) {
                            // ensure CRS is passed to the Geometry object
                            Geometry geometry = (Geometry) value;
                            CoordinateReferenceSystem crs = ((GeometryAttribute) property)
                                    .getDescriptor().getCoordinateReferenceSystem();
                            Map<Object, Object> userData = new HashMap<Object, Object>();
                            Object obj = geometry.getUserData();
                            if (obj != null && obj instanceof Map) {
                                userData.putAll((Map) obj);
                            }
                            userData.put(CoordinateReferenceSystem.class, crs);
                            geometry.setUserData(userData);
                        }
                    } else {
                        // non-complex bindings are unpacked as for simple feature case
                        value = property.getValue();
                    }
                    properties.add(new Object[] { particle, value });
                }
            }
        }

        return properties;
    }
   
    public XSDTypeDefinition createXmlTypeFromFeatureType(SimpleFeatureType featureType, SchemaIndex schemaIndex, Set<String> toFilter ) {
        XSDFactory f = XSDFactory.eINSTANCE;
        Document dom;
        try {
            dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
        } catch (ParserConfigurationException e) {
            throw new RuntimeException( e );
        }
       
        XSDComplexTypeDefinition type = f.createXSDComplexTypeDefinition();
        type.setTargetNamespace( featureType.getName().getNamespaceURI() );
        type.setName( featureType.getTypeName() + "Type" );
        type.setDerivationMethod(XSDDerivationMethod.EXTENSION_LITERAL);
        type.setBaseTypeDefinition(schemaIndex.getTypeDefinition( gml.qName("AbstractFeatureType") ) );
               
        XSDModelGroup group = f.createXSDModelGroup();
        group.setCompositor(XSDCompositor.SEQUENCE_LITERAL);

        List attributes = featureType.getAttributeDescriptors();
        for (int i = 0; i < attributes.size(); i++) {
            AttributeDescriptor attribute = (AttributeDescriptor) attributes.get(i);

            if ( toFilter.contains( attribute.getLocalName() ) ) {
                continue;
            }
          
            XSDElementDeclaration element = f.createXSDElementDeclaration();
            element.setName(attribute.getLocalName());
            element.setNillable(attribute.isNillable());

            //check for geometry
            if ( attribute instanceof GeometryDescriptor ) {
                Class binding = attribute.getType().getBinding();
                if ( Point.class.isAssignableFrom( binding ) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("PointPropertyType")));
                }
                else if ( LineString.class.isAssignableFrom( binding ) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("LineStringPropertyType")));
                }
                else if ( Polygon.class.isAssignableFrom( binding) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("PolygonPropertyType")));
                }
                else if ( MultiPoint.class.isAssignableFrom( binding ) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("MultiPointPropertyType")));
                }
                else if ( MultiLineString.class.isAssignableFrom( binding ) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("MultiLineStringPropertyType")));
                }
                else if ( MultiPolygon.class.isAssignableFrom( binding) ) {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("MultiPolygonPropertyType")));
                }
                else {
                    element.setTypeDefinition( schemaIndex.getTypeDefinition(gml.qName("GeometryPropertyType")));
                }
            }
            else {
                //TODO: do a proper mapping
                element.setTypeDefinition(schemaIndex.getTypeDefinition(XS.STRING));
            }
           

            XSDParticle particle = f.createXSDParticle();
            particle.setMinOccurs(attribute.getMinOccurs());
            particle.setMaxOccurs(attribute.getMaxOccurs());
            particle.setContent(element);
            particle.setElement( dom.createElementNS( XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, "element" ) );
           
            group.getContents().add(particle);
        }

        XSDParticle particle = f.createXSDParticle();
        particle.setContent(group);
        particle.setElement( dom.createElementNS( XSDConstants.SCHEMA_FOR_SCHEMA_URI_2001, "sequence") );
        type.setContent(particle);
        return type;
    }
   
    /**
     * Return true if name is the name of a descriptor of the type or of an ancestor type.
     *
     * @param type type to test
     * @param name name of descriptor
     * @return true if the type or an ancestor has a descriptor of this name
     */
    private boolean isValidDescriptor(ComplexType type, Name name) {
        if (type.getDescriptor(name) != null) {
            return true;
        } else if (type.getSuper() instanceof ComplexType) {
            return isValidDescriptor((ComplexType) type.getSuper(), name);
        } else {
            return false;
        }
    }
   
    /**
     * Return gml:boundedBy property if wanted.
     *
     * @param feature
     *            feature for which bounds might be required
     * @param configuration
     *            encoder configuration, used to suppress feature bounds
     * @return the feature bounds, or null if none or unwanted
     */
    private BoundingBox getBoundedBy(Feature feature, Configuration configuration) {
        // check for flag not to include bounds
        if (configuration.hasProperty(GMLConfiguration.NO_FEATURE_BOUNDS)) {
            return null;
        } else {
            BoundingBox bounds = feature.getBounds();
            // do a check for the case where the feature has no geometry properties
            if (bounds.isEmpty()
                    && (feature.getDefaultGeometryProperty() == null || feature
                            .getDefaultGeometryProperty().getValue() == null)) {
                return null;
            } else {
                return bounds;
            }
        }
    }


    public Object GeometryPropertyType_getProperty(Geometry geometry, QName name) {
        return GeometryPropertyType_getProperty(geometry, name, true, false);
    }

    public Object GeometryPropertyType_getProperty(Geometry geometry, QName name,
            boolean includeAbstractGeometry) {
        return GeometryPropertyType_getProperty(geometry, name, includeAbstractGeometry, false);

    }

    public Object GeometryPropertyType_getProperty(Geometry geometry, QName name,
            boolean includeAbstractGeometry, boolean makeEmpty) {

        if (name.equals(gml.qName("Point")) || name.equals(gml.qName("LineString"))
                || name.equals(gml.qName("Polygon")) || name.equals(gml.qName("MultiPoint"))
                || name.equals(gml.qName("MultiLineString"))
                || name.equals(gml.qName("MultiPolygon")) || name.equals(gml.qName("MultiSurface"))
                || name.equals(gml.qName("AbstractSurface")) || name.equals(gml.qName("_Surface"))
                || name.equals(gml.qName("_Curve")) || name.equals(gml.qName("AbstractCurve"))
                || name.equals(gml.qName("MultiCurve"))
                || (includeAbstractGeometry && (name.equals(gml.qName("_Geometry"))
                                                || name.equals(gml.qName("AbstractGeometry"))))) {
            // if the geometry is null, return null
            if (isEmpty(geometry) || makeEmpty) {
                return null;
            }

            return geometry;
        }

        if (geometry.getUserData() instanceof Map) {
            Map<Name, Object> clientProperties = (Map<Name, Object>) ((Map) geometry.getUserData())
                    .get(Attributes.class);

            Name cname = toTypeName(name);
            if (clientProperties != null && clientProperties.keySet().contains(cname))
                return clientProperties.get(cname);
        }

        if (XLINK.HREF.equals(name)) {
            // only process if geometry is empty and ID exists
            String id = getID(geometry);
            if ((makeEmpty || isEmpty(geometry)) && id != null) {
                return "#" + id;
            }
        }

        return null;

    }

    /**
     * Convert a {@link QName} to a {@link Name}.
     *
     * @param name
     * @return
     */
    private static Name toTypeName(QName name) {
        if (XMLConstants.NULL_NS_URI.equals(name.getNamespaceURI())) {
            return new NameImpl(name.getLocalPart());
        } else {
            return new NameImpl(name.getNamespaceURI(), name.getLocalPart());
        }
    }
   
    public List GeometryPropertyType_getProperties(Geometry geometry) {
        return null;
    }
   
    public static boolean isEmpty( Geometry geometry ) {
        if ( geometry.isEmpty() ) {
            //check for case of multi geometry, if it has > 0 goemetries
            // we consider this to be not empty
            if ( geometry instanceof GeometryCollection ) {
                if ( ((GeometryCollection) geometry).getNumGeometries() != 0 ) {
                    return false;
                }
            }
            return true;
        }
       
        return false;
    }
   
    /**
     * Determines the identifier (gml:id) of the geometry by checking
     * {@link Geometry#getUserData()}.
     * <p>
     * This method returns <code>null</code> when no id can be found.
     * </p>
     */
    public String getID(Geometry g) {
        return getMetadata( g, "gml:id" );
    }
   
    /**
     * Set the identifier (gml:id) of the geometry as a key in the user data map
     * {@link Geometry#getUserData()} (creating it with{@link Geometry#getUserData()}
     * if it does not already exist). If the user data exists and is not a
     * {@link Map}, this method has no effect.
     *
     * @param g the geometry
     * @param id the gml:id to be set
     */
    public void setID(Geometry g, String id) {
        setMetadata(g, "gml:id", id);
    }
   
    /**
     * Determines the description (gml:description) of the geometry by checking
     * {@link Geometry#getUserData()}.
     * <p>
     * This method returns <code>null</code> when no name can be found.
     * </p>
     */
    public String getName(Geometry g) {
        return getMetadata( g, "gml:name" );
    }
   
    /**
     * Set the name (gml:name) of the geometry as a key in the user data map
     * {@link Geometry#getUserData()} (creating it with{@link Geometry#getUserData()}
     * if it does not already exist). If the user data exists and is not a
     * {@link Map}, this method has no effect.
     *
     * @param g the geometry
     * @param name the gml:name to be set
     */
    public void setName(Geometry g, String name) {
        setMetadata(g, "gml:name", name);
    }
   
    /**
     * Determines the name (gml:name) of the geometry by checking
     * {@link Geometry#getUserData()}.
     * <p>
     * This method returns <code>null</code> when no description can be found.
     * </p>
     */
    public String getDescription(Geometry g) {
        return getMetadata( g, "gml:description" );
    }
   
    /**
     * Set the description (gml:description) of the geometry as a key in the user data map
     * {@link Geometry#getUserData()} (creating it with{@link Geometry#getUserData()}
     * if it does not already exist). If the user data exists and is not a
     * {@link Map}, this method has no effect.
     *
     * @param g the geometry
     * @param description the gml:description to be set
     */
    public void setDescription(Geometry g, String description) {
        setMetadata(g, "gml:description", description);
    }
   
    @SuppressWarnings("rawtypes")
    String getMetadata(Geometry g, String metadata) {
        if (g.getUserData() instanceof Map) {
            Map userData = (Map) g.getUserData();
            return (String) userData.get(metadata);
        }
        return null;
    }
   
    @SuppressWarnings({ "unchecked", "rawtypes" })
    void setMetadata(Geometry g, String metadata, String value) {
        if (g.getUserData() == null) {
            g.setUserData(new HashMap());
        }
        if (g.getUserData() instanceof Map) {
            ((Map) g.getUserData()).put(metadata, value);
        }
    }

}
TOP

Related Classes of org.geotools.gml2.bindings.GMLEncodingUtils

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.