/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2009-2016, Geomatys
*
* 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.geotoolkit.feature.xml.jaxb;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.net.URL;
import java.util.AbstractMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import org.apache.sis.util.collection.Cache;
import org.apache.sis.util.logging.Logging;
import org.apache.sis.xml.MarshallerPool;
import org.geotoolkit.feature.xml.Utils;
import org.geotoolkit.xsd.xml.v2001.Appinfo;
import org.geotoolkit.xsd.xml.v2001.Attribute;
import org.geotoolkit.xsd.xml.v2001.ComplexType;
import org.geotoolkit.xsd.xml.v2001.Element;
import org.geotoolkit.xsd.xml.v2001.Import;
import org.geotoolkit.xsd.xml.v2001.Include;
import org.geotoolkit.xsd.xml.v2001.LocalSimpleType;
import org.geotoolkit.xsd.xml.v2001.NamedAttributeGroup;
import org.geotoolkit.xsd.xml.v2001.NamedGroup;
import org.geotoolkit.xsd.xml.v2001.OpenAttrs;
import org.geotoolkit.xsd.xml.v2001.Schema;
import org.geotoolkit.xsd.xml.v2001.SimpleType;
import org.geotoolkit.xsd.xml.v2001.TopLevelElement;
import org.geotoolkit.xsd.xml.v2001.XSDMarshallerPool;
import org.opengis.feature.MismatchedFeatureException;
import org.w3c.dom.Node;
/**
* Store location and relations in sxd schemas.
*
* @author Johann Sorel (Geomatys)
*/
public class XSDSchemaContext {
private static final Logger LOGGER = Logging.getLogger("org.geotoolkit.feature.xml.jaxp");
private static final MarshallerPool POOL = XSDMarshallerPool.getInstance();
private static final Cache<String,Schema> SCHEMA_CACHE = new Cache<>(60,60,true);
/**
* default relocations
* used by all reader instances
*/
private static final Map<String,String> RELOCATIONS = new HashMap<>();
static {
//GML 3.1.1
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/gml.xsd","/xsd/gml/3.1.1/gml.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/dynamicFeature.xsd","/xsd/gml/3.1.1/dynamicFeature.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/feature.xsd","/xsd/gml/3.1.1/feature.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/geometryBasic2d.xsd","/xsd/gml/3.1.1/geometryBasic2d.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/geometryBasic0d1d.xsd","/xsd/gml/3.1.1/geometryBasic0d1d.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/measures.xsd","/xsd/gml/3.1.1/measures.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/units.xsd","/xsd/gml/3.1.1/units.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/dictionary.xsd","/xsd/gml/3.1.1/dictionary.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/gmlBase.xsd","/xsd/gml/3.1.1/gmlBase.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/basicTypes.xsd","/xsd/gml/3.1.1/basicTypes.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/temporal.xsd","/xsd/gml/3.1.1/temporal.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/direction.xsd","/xsd/gml/3.1.1/direction.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/topology.xsd","/xsd/gml/3.1.1/topology.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/geometryComplexes.xsd","/xsd/gml/3.1.1/geometryComplexes.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/geometryAggregates.xsd","/xsd/gml/3.1.1/geometryAggregates.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/geometryPrimitives.xsd","/xsd/gml/3.1.1/geometryPrimitives.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/coverage.xsd","/xsd/gml/3.1.1/coverage.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/valueObjects.xsd","/xsd/gml/3.1.1/valueObjects.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/grids.xsd","/xsd/gml/3.1.1/grids.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/coordinateReferenceSystems.xsd","/xsd/gml/3.1.1/coordinateReferenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/coordinateSystems.xsd","/xsd/gml/3.1.1/coordinateSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/referenceSystems.xsd","/xsd/gml/3.1.1/referenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/datums.xsd","/xsd/gml/3.1.1/datums.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/coordinateOperations.xsd","/xsd/gml/3.1.1/coordinateOperations.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/dataQuality.xsd","/xsd/gml/3.1.1/dataQuality.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/observation.xsd","/xsd/gml/3.1.1/observation.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/defaultStyle.xsd","/xsd/gml/3.1.1/defaultStyle.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/smil/smil20.xsd","/xsd/gml/3.1.1/smil20.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/smil/smil20-language.xsd","/xsd/gml/3.1.1/smil20-language.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/temporalReferenceSystems.xsd","/xsd/gml/3.1.1/temporalReferenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.1.1/base/temporalTopology.xsd","/xsd/gml/3.1.1/temporalTopology.xsd");
//GML 3.2.1
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/gml.xsd","/xsd/gml/3.2.1/gml.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/dynamicFeature.xsd","/xsd/gml/3.2.1/dynamicFeature.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/feature.xsd","/xsd/gml/3.2.1/feature.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/geometryAggregates.xsd","/xsd/gml/3.2.1/geometryAggregates.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/geometryPrimitives.xsd","/xsd/gml/3.2.1/geometryPrimitives.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/geometryBasic2d.xsd","/xsd/gml/3.2.1/geometryBasic2d.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/geometryBasic0d1d.xsd","/xsd/gml/3.2.1/geometryBasic0d1d.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/measures.xsd","/xsd/gml/3.2.1/measures.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/units.xsd","/xsd/gml/3.2.1/units.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/dictionary.xsd","/xsd/gml/3.2.1/dictionary.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/gmlBase.xsd","/xsd/gml/3.2.1/gmlBase.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/basicTypes.xsd","/xsd/gml/3.2.1/basicTypes.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/temporal.xsd","/xsd/gml/3.2.1/temporal.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/direction.xsd","/xsd/gml/3.2.1/direction.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/topology.xsd","/xsd/gml/3.2.1/topology.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/geometryComplexes.xsd","/xsd/gml/3.2.1/geometryComplexes.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/coverage.xsd","/xsd/gml/3.2.1/coverage.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/valueObjects.xsd","/xsd/gml/3.2.1/valueObjects.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/grids.xsd","/xsd/gml/3.2.1/grids.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/coordinateReferenceSystems.xsd","/xsd/gml/3.2.1/coordinateReferenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/coordinateSystems.xsd","/xsd/gml/3.2.1/coordinateSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/referenceSystems.xsd","/xsd/gml/3.2.1/referenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/datums.xsd","/xsd/gml/3.2.1/datums.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/coordinateOperations.xsd","/xsd/gml/3.2.1/coordinateOperations.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/observation.xsd","/xsd/gml/3.2.1/observation.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/temporalReferenceSystems.xsd","/xsd/gml/3.2.1/temporalReferenceSystems.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/temporalTopology.xsd","/xsd/gml/3.2.1/temporalTopology.xsd");
RELOCATIONS.put("http://schemas.opengis.net/gml/3.2.1/deprecatedTypes.xsd","/xsd/gml/3.2.1/deprecatedTypes.xsd");
//ISO 19139 Metadata
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/gmd.xsd","/xsd/iso/19139/20070417/gmd/gmd.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/metadataApplication.xsd","/xsd/iso/19139/20070417/gmd/metadataApplication.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/metadataEntity.xsd","/xsd/iso/19139/20070417/gmd/metadataEntity.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/spatialRepresentation.xsd","/xsd/iso/19139/20070417/gmd/spatialRepresentation.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/citation.xsd","/xsd/iso/19139/20070417/gmd/citation.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/referenceSystem.xsd","/xsd/iso/19139/20070417/gmd/referenceSystem.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/extent.xsd","/xsd/iso/19139/20070417/gmd/extent.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/metadataExtension.xsd","/xsd/iso/19139/20070417/gmd/metadataExtension.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/content.xsd","/xsd/iso/19139/20070417/gmd/content.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/applicationSchema.xsd","/xsd/iso/19139/20070417/gmd/applicationSchema.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/portrayalCatalogue.xsd","/xsd/iso/19139/20070417/gmd/portrayalCatalogue.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/dataQuality.xsd","/xsd/iso/19139/20070417/gmd/dataQuality.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/identification.xsd","/xsd/iso/19139/20070417/gmd/identification.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/constraints.xsd","/xsd/iso/19139/20070417/gmd/constraints.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/distribution.xsd","/xsd/iso/19139/20070417/gmd/distribution.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/maintenance.xsd","/xsd/iso/19139/20070417/gmd/maintenance.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gmd/freeText.xsd","/xsd/iso/19139/20070417/gmd/freeText.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gco/gco.xsd","/xsd/iso/19139/20070417/gco/gco.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gco/basicTypes.xsd","/xsd/iso/19139/20070417/gco/basicTypes.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gco/gcoBase.xsd","/xsd/iso/19139/20070417/gco/gcoBase.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gss/gss.xsd","/xsd/iso/19139/20070417/gss/gss.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gss/geometry.xsd","/xsd/iso/19139/20070417/gss/geometry.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gts/gts.xsd","/xsd/iso/19139/20070417/gts/gts.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gts/temporalObjects.xsd","/xsd/iso/19139/20070417/gts/temporalObjects.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gsr/gsr.xsd","/xsd/iso/19139/20070417/gsr/gsr.xsd");
RELOCATIONS.put("http://schemas.opengis.net/iso/19139/20070417/gsr/spatialReferencing.xsd","/xsd/iso/19139/20070417/gsr/spatialReferencing.xsd");
//XML
RELOCATIONS.put("http://www.w3.org/1999/xlink.xsd","/xsd/1999/xlink.xsd");
RELOCATIONS.put("http://www.w3.org/2001/xml.xsd","/xsd/2001/xml.xsd");
}
final Map<String,Schema> knownSchemas = new HashMap<>();
final Map<String,String> locationMap = new HashMap<>();
//Substitution group hierarchy
// example : AbstractGeometry -> [AbstractGeometricAggregate,AbstractGeometricPrimitive,GeometricComplex,AbstractImplicitGeometry]
final Map<QName,Set<QName>> substitutionGroups = new HashMap<>();
/**
* Target namespace of the primary XSD.
*/
String targetNamespace;
public XSDSchemaContext(Map<String,String> locationMap) {
//default relocations
this.locationMap.putAll(RELOCATIONS);
if(locationMap!=null){
this.locationMap.putAll(locationMap);
}
}
/**
*
* @param candidate
* @param name
* @return
* @throws JAXBException
*/
public Schema read(final Object candidate, final String name) throws JAXBException {
try {
final Unmarshaller unmarshaller = POOL.acquireUnmarshaller();
final Schema schema;
String baseLocation = null;
if(candidate instanceof Node) schema = (Schema) unmarshaller.unmarshal((Node)candidate);
else if(candidate instanceof Reader) schema = (Schema) unmarshaller.unmarshal((Reader)candidate);
else if(candidate instanceof InputStream) schema = (Schema) unmarshaller.unmarshal((InputStream)candidate);
else if(candidate instanceof String) schema = (Schema) unmarshaller.unmarshal(new StringReader((String)candidate));
else if(candidate instanceof URL){
schema = (Schema) unmarshaller.unmarshal(((URL)candidate).openStream());
// we build the base url to retrieve imported xsd
final String location = ((URL)candidate).toString();
knownSchemas.put(location, schema);
if (location.lastIndexOf('/') != -1) {
baseLocation = location.substring(0, location.lastIndexOf('/') + 1);
} else {
baseLocation = location;
}
}
else throw new JAXBException("Unsupported input type : "+candidate);
POOL.recycle(unmarshaller);
knownSchemas.put("unknow location", schema);
return schema;
} catch (IOException ex) {
throw new JAXBException(ex.getMessage(),ex);
}
}
/**
*
* @param candidate
* @return Map<Schema,Location>
* @throws JAXBException
*/
public Map.Entry<Schema,String> read(final Object candidate) throws JAXBException {
try {
final Unmarshaller unmarshaller = POOL.acquireUnmarshaller();
final Schema schema;
String baseLocation = null;
if(candidate instanceof Node) schema = (Schema) unmarshaller.unmarshal((Node)candidate);
else if(candidate instanceof Reader) schema = (Schema) unmarshaller.unmarshal((Reader)candidate);
else if(candidate instanceof InputStream) schema = (Schema) unmarshaller.unmarshal((InputStream)candidate);
else if(candidate instanceof String) schema = (Schema) unmarshaller.unmarshal(new StringReader((String)candidate));
else if(candidate instanceof URL){
schema = (Schema) unmarshaller.unmarshal(((URL)candidate).openStream());
// we build the base url to retrieve imported xsd;
final String location = ((URL)candidate).toString();
knownSchemas.put(location, schema);
if (location.lastIndexOf('/') != -1) {
baseLocation = location.substring(0, location.lastIndexOf('/') + 1);
} else {
baseLocation = location;
}
}
else throw new JAXBException("Unsupported input type : "+candidate);
POOL.recycle(unmarshaller);
targetNamespace = schema.getTargetNamespace();
knownSchemas.put("unknow location", schema);
return new AbstractMap.SimpleImmutableEntry<>(schema, baseLocation);
} catch (IOException ex) {
throw new JAXBException(ex.getMessage(),ex);
}
}
public void listAllSchemas(final Schema schema, final String baseLocation, List<Map.Entry<Schema,String>> refs) throws MismatchedFeatureException{
fillAllSubstitution(schema);
for (OpenAttrs attr: schema.getIncludeOrImportOrRedefine()) {
if (attr instanceof Import || attr instanceof Include) {
final String schemalocation = Utils.getIncludedLocation(baseLocation, attr);
if (schemalocation != null && !knownSchemas.containsKey(schemalocation)) {
//check for a relocation
final String relocation = locationMap.get(schemalocation);
final String finalLocation = (relocation==null) ? schemalocation : relocation;
Schema importedSchema = null;
try{
importedSchema = SCHEMA_CACHE.getOrCreate(finalLocation, new Callable() {
public Schema call() {
return Utils.getDistantSchema(finalLocation);
}
});
}catch(Exception ex){
throw new MismatchedFeatureException(ex.getMessage(),ex);
}
if (importedSchema != null) {
knownSchemas.put(schemalocation, importedSchema);
final String newBaseLocation = getNewBaseLocation(schemalocation, baseLocation);
refs.add(new AbstractMap.SimpleEntry<>(importedSchema, newBaseLocation));
//recursive search of all imports and include
listAllSchemas(importedSchema, newBaseLocation, refs);
} else {
LOGGER.log(Level.WARNING, "Unable to retrieve imported schema:{0}", schemalocation);
}
}
}
}
}
public ComplexType findComplexType(QName typeName) {
for (Map.Entry<String,Schema> entry : knownSchemas.entrySet()) {
final Schema schema = entry.getValue();
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
final ComplexType type = schema.getComplexTypeByName(typeName.getLocalPart());
if (type != null) {
return type;
}
}
return null;
}
/**
* list all elements and complexe types and put them in the allCache map.
* Do not parse them yet.
*
* @param schema
*/
private void fillAllSubstitution(Schema schema){
for(OpenAttrs att : schema.getSimpleTypeOrComplexTypeOrGroup()){
if(att instanceof TopLevelElement){
final TopLevelElement ele = (TopLevelElement) att;
final QName parent = ele.getSubstitutionGroup();
if(parent!=null){
Set<QName> subList = substitutionGroups.get(parent);
if(subList==null){
subList = new HashSet<>();
substitutionGroups.put(parent, subList);
}
final QName name = new QName(schema.getTargetNamespace(), ele.getName());
if(subList.contains(name)){
//name already here, check if one of them is deprecated
subList.add(name);
}else{
subList.add(name);
}
}
}
}
}
private String getNewBaseLocation(final String schemalocation, final String oldBaseLocation) {
final String newBaseLocation;
if (schemalocation.lastIndexOf('/') != -1) {
newBaseLocation = schemalocation.substring(0, schemalocation.lastIndexOf('/') + 1);
} else {
newBaseLocation = oldBaseLocation;
}
return newBaseLocation;
}
public NamedGroup findGlobalGroup(final QName typeName) {
// look in the schemas
for (Entry<String,Schema> entry : knownSchemas.entrySet()) {
final Schema schema = entry.getValue();
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
for(OpenAttrs att : schema.getSimpleTypeOrComplexTypeOrGroup()){
if(att instanceof NamedGroup){
final NamedGroup candidate = (NamedGroup) att;
if(candidate.getName().equals(typeName.getLocalPart())){
return candidate;
}
}
}
}
return null;
}
public Attribute findGlobalAttribute(final QName typeName) {
// look in the schemas
for (Entry<String,Schema> entry : knownSchemas.entrySet()) {
final Schema schema = entry.getValue();
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
for(OpenAttrs att : schema.getSimpleTypeOrComplexTypeOrGroup()){
if(att instanceof Attribute){
final Attribute candidate = (Attribute) att;
if(candidate.getName().equals(typeName.getLocalPart())){
return candidate;
}
}
}
}
return null;
}
public Element findGlobalElement(final QName typeName){
Element element = null;
// look in the schemas
for (Entry<String,Schema> entry : knownSchemas.entrySet()) {
final Schema schema = entry.getValue();
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
loop:
for(OpenAttrs att : schema.getSimpleTypeOrComplexTypeOrGroup()){
if(att instanceof Element){
final TopLevelElement candidate = (TopLevelElement) att;
if(candidate.getName().equals(typeName.getLocalPart())){
//check if it's a deprecated type, we will return it only in last case
if(isDeprecated(candidate)){
element = candidate;
continue loop;
}
//found it
return candidate;
}
}
}
}
return element;
}
public NamedAttributeGroup findAttributeGroup(final QName typeName){
// look in the schemas
for (Entry<String,Schema> entry : knownSchemas.entrySet()) {
final Schema schema = entry.getValue();
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
for(OpenAttrs att : schema.getSimpleTypeOrComplexTypeOrGroup()){
if(att instanceof NamedAttributeGroup){
final NamedAttributeGroup candidate = (NamedAttributeGroup) att;
if(candidate.getName().equals(typeName.getLocalPart())){
return candidate;
}
}
}
}
return null;
}
public SimpleType findSimpleType(final QName typeName) {
// look in the schemas
for (Schema schema : knownSchemas.values()) {
if(!schema.getTargetNamespace().equalsIgnoreCase(typeName.getNamespaceURI())) continue;
final SimpleType type = schema.getSimpleTypeByName(typeName.getLocalPart());
if (type != null) {
return type;
}
}
// look in primitive types
if (Utils.existPrimitiveType(typeName.getLocalPart())) {
return new LocalSimpleType(typeName.getLocalPart());
}
return null;
}
public Set<QName> getSubstitutions(QName name){
final Set<QName> subs = new HashSet<>();
final Set<QName> lst = substitutionGroups.get(name);
if(lst!=null){
for(QName sub : lst){
subs.add(sub);
subs.addAll(getSubstitutions(sub));
}
}
return subs;
}
/**
* Check if the given complex type inherit from FeatureType.
*
* @param search
* @return true if this type is a feature type.
*/
public boolean isFeatureType(ComplexType search){
//loop on parent types until we find a Feature type
while(search!=null){
if(search.extendFeature()) return true;
if(search.getComplexContent()==null || search.getComplexContent().getExtension()==null) break;
final QName base = search.getComplexContent().getExtension().getBase();
search = findComplexType(base);
}
return false;
}
public static boolean isDeprecated(TopLevelElement candidate){
//check if it's a deprecated type, we will return it only in last case
if(candidate.getAnnotation()!=null){
for(Object obj : candidate.getAnnotation().getAppinfoOrDocumentation()){
if(obj instanceof Appinfo){
for(Object cdt : ((Appinfo)obj).getContent()){
if(cdt instanceof String && "deprecated".equalsIgnoreCase((String)cdt)){
return true;
}
}
}
}
}
return false;
}
}