/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2009-2015, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotools.gml3.complex; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.eclipse.xsd.XSDAttributeDeclaration; import org.eclipse.xsd.XSDAttributeUse; import org.eclipse.xsd.XSDAttributeUseCategory; import org.eclipse.xsd.XSDComplexTypeDefinition; import org.eclipse.xsd.XSDSchema; import org.eclipse.xsd.XSDTypeDefinition; import org.geotools.gml3.GML; import org.geotools.gml3.GMLConfiguration; import org.geotools.gml3.GMLSchema; import org.geotools.gml3.smil.SMIL20LANGSchema; import org.geotools.gml3.smil.SMIL20Schema; import org.geotools.xml.Configuration; import org.geotools.xml.SchemaIndex; import org.geotools.xml.Schemas; import org.geotools.xml.complex.FeatureTypeRegistryConfiguration; import org.geotools.xs.XS; import org.opengis.feature.type.Name; import org.opengis.feature.type.Schema; import org.geotools.feature.type.Types; /** * Feature Type Registry Configuration for GML. Depending on the schema type * different version of GML class may be called upon. eg {@link org.geotools.gml3.v3_2.GML} or * {@link org.geotools.gml3.GML} * * @author Victor Tey, CSIRO Exploration and Mining * @author Niels Charlier * */ public class GmlFeatureTypeRegistryConfiguration implements FeatureTypeRegistryConfiguration { String namespace; public GmlFeatureTypeRegistryConfiguration(String uri) { if (uri != null) { namespace = uri; } else { namespace = ""; } } @Override public Collection<Schema> getSchemas() { ArrayList<Schema> schemas = new ArrayList<Schema>(); schemas.add(new SMIL20Schema()); schemas.add(new SMIL20LANGSchema()); schemas.add(new GMLSchema());; schemas.add(new org.geotools.gml3.v3_2.GMLSchema()); schemas.add(new org.geotools.gml3.v3_2.gco.GCOSchema()); schemas.add(new org.geotools.gml3.v3_2.gmd.GMDSchema()); schemas.add(new org.geotools.gml3.v3_2.gmx.GMXSchema()); schemas.add(new org.geotools.gml3.v3_2.gsr.GSRSchema()); schemas.add(new org.geotools.gml3.v3_2.gss.GSSSchema()); schemas.add(new org.geotools.gml3.v3_2.gts.GTSSchema()); return schemas; } @Override public Collection<Configuration> getConfigurations() { ArrayList<Configuration> configurations = new ArrayList<Configuration>(); configurations.add(new GMLConfiguration()); configurations.add(new org.geotools.gml3.v3_2.GMLConfiguration()); return configurations; } public QName getAbstractFeatureType() { if (namespace.equals(org.geotools.gml3.v3_2.GML.NAMESPACE)) { return org.geotools.gml3.v3_2.GML.AbstractFeatureType; } else { return org.geotools.gml3.GML.AbstractFeatureType; } } public QName getAbstractGeometryType() { if (namespace.equals(org.geotools.gml3.v3_2.GML.NAMESPACE)) { return org.geotools.gml3.v3_2.GML.AbstractGeometryType; } else { return org.geotools.gml3.GML.AbstractGeometryType; } } public String getNameSpace() { if (namespace.equals(org.geotools.gml3.v3_2.GML.NAMESPACE)) { return org.geotools.gml3.v3_2.GML.NAMESPACE; } else { return org.geotools.gml3.GML.NAMESPACE; } } public QName getId() { if (namespace.equals(org.geotools.gml3.v3_2.GML.NAMESPACE)) { return org.geotools.gml3.v3_2.GML.id; } else { return org.geotools.gml3.GML.id; } } public void setEmptyNamespace(XSDTypeDefinition typeDefinition) { if (namespace.isEmpty()) { // GEOT-4756: // namespace could be unset when GML namespace is not set in the mapping file // which is valid when it's not used in the mapping if (isBasedOn(typeDefinition, org.geotools.gml3.v3_2.GML.NAMESPACE)) { namespace = org.geotools.gml3.v3_2.GML.NAMESPACE; } else if (isBasedOn(typeDefinition, org.geotools.gml3.GML.NAMESPACE)) { namespace = org.geotools.gml3.GML.NAMESPACE; } } } @Override public boolean isFeatureType(XSDTypeDefinition typeDefinition) { setEmptyNamespace(typeDefinition); return isDerivedFrom(typeDefinition, getAbstractFeatureType()); } @Override public boolean isGeometryType(XSDTypeDefinition typeDefinition) { setEmptyNamespace(typeDefinition); return isDerivedFrom(typeDefinition, getAbstractGeometryType()); } @Override public boolean isIdentifiable(XSDComplexTypeDefinition typeDefinition) { List attributeUses = typeDefinition.getAttributeUses(); final String idAttName = getId().getLocalPart(); for (Iterator it = attributeUses.iterator(); it.hasNext();) { XSDAttributeUse use = (XSDAttributeUse) it.next(); XSDAttributeUseCategory useCategory = use.getUse(); XSDAttributeDeclaration idAtt = use.getAttributeDeclaration(); String targetNamespace = idAtt.getTargetNamespace(); String name = idAtt.getName(); if (getNameSpace().equals(targetNamespace) && idAttName.equals(name)) { if (XSDAttributeUseCategory.REQUIRED_LITERAL.equals(useCategory)) { return true; } } } return false; } /** * Returns true if the <code>typeDefinition</code> is based on provided <code>superNS</code>. * * @param typeDefinition * @param superNS * @return */ private static boolean isBasedOn(XSDTypeDefinition typeDefinition, final String superNS) { XSDTypeDefinition baseType; String targetNamespace; String name; while ((baseType = typeDefinition.getBaseType()) != null) { targetNamespace = baseType.getTargetNamespace(); name = baseType.getName(); if (XS.NAMESPACE.equals(targetNamespace) && XS.ANYTYPE.getLocalPart().equals(name)) { // break the loop or this goes forever return false; } if (superNS.equals(targetNamespace)) { return true; } typeDefinition = baseType; } return false; } /** * Returns whether <code>typeDefinition</code> has an ancestor named <code>baseTypeName</code>. * * @param typeDefinition * @param baseTypeName * @return */ private static boolean isDerivedFrom(final XSDTypeDefinition typeDefinition, final QName baseTypeName) { return isDerivedFrom(typeDefinition, Types.toTypeName(baseTypeName)); } /** * Returns <code>true</code> if <code>typeDefinition</code> is derived from a type named * <code>superTypeName</code> * * @param typeDefinition * @param superTypeName * @return */ private static boolean isDerivedFrom(XSDTypeDefinition typeDefinition, final Name superTypeName) { XSDTypeDefinition baseType; final String superNS = superTypeName.getNamespaceURI(); final String superName = superTypeName.getLocalPart(); String targetNamespace; String name; while ((baseType = typeDefinition.getBaseType()) != null) { targetNamespace = baseType.getTargetNamespace(); name = baseType.getName(); if (XS.NAMESPACE.equals(targetNamespace) && XS.ANYTYPE.getLocalPart().equals(name)) { return false; } if (superNS.equals(targetNamespace) && superName.equals(name)) { return true; } typeDefinition = baseType; } return false; } /** * Map of the qualified-name of a known type in each supported GML version to the {@link Configuration} for that GML version. */ @SuppressWarnings("serial") private static final Map<QName, Class<? extends Configuration>> SUPPORTED_GML_KNOWN_TYPE_TO_CONFIGURATION_MAP // = new LinkedHashMap<QName, Class<? extends Configuration>>() { { // GML 3.1 put(GML.AbstractFeatureType, GMLConfiguration.class); // GML 3.2 put(org.geotools.gml3.v3_2.GML.AbstractFeatureType, org.geotools.gml3.v3_2.GMLConfiguration.class); } }; public static Configuration findGmlConfiguration(Configuration configuration) { SchemaIndex index = null; try { index = Schemas.findSchemas(configuration); for (QName name : SUPPORTED_GML_KNOWN_TYPE_TO_CONFIGURATION_MAP.keySet()) { XSDTypeDefinition type = index.getTypeDefinition(name); if (type != null) { try { return SUPPORTED_GML_KNOWN_TYPE_TO_CONFIGURATION_MAP.get(name).newInstance(); } catch (Exception e) { throw new RuntimeException(e); } } } for (XSDSchema schema : index.getSchemas()) { String ns = schema.getTargetNamespace(); if (ns != null && ns.startsWith("http://www.opengis.net/gml")) { throw new RuntimeException("Unsupported GML version for schema at " + configuration.getXSD().getSchemaLocation()); } } } finally { if (index != null) { index.destroy(); } } return null; } }