/*
* GeotoolKit - An Open Source Java GIS Toolkit
* http://geotoolkit.org
*
* (C) 2009, 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.catalog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.apache.sis.internal.jaxb.gco.GO_GenericName;
import org.geotoolkit.resources.jaxb.feature.catalog.FeatureCatalogueAdapter;
import org.opengis.util.LocalName;
import org.opengis.feature.catalog.Constraint;
import org.opengis.feature.catalog.DefinitionReference;
import org.opengis.feature.catalog.FeatureAttribute;
import org.opengis.feature.catalog.FeatureCatalogue;
import org.opengis.feature.catalog.FeatureType;
import org.opengis.feature.catalog.InheritanceRelation;
import org.opengis.feature.catalog.PropertyType;
/**
* Class of real world phenomena with common properties - - [ocl] - name realizes GF_FeatureType::typeName; - isAbstract realizes GF_FeatureType::isAbstract; - constrainedBy realizes GF_FeatureType::constrainedBy - [/ocl]
*
* <p>Java class for FC_FeatureType_Type complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* <complexType name="FC_FeatureType_Type">
* <complexContent>
* <extension base="{http://www.isotc211.org/2005/gco}AbstractObject_Type">
* <sequence>
* <element name="typeName" type="{http://www.isotc211.org/2005/gco}LocalName_Impl"/>
* <element name="definition" type="{http://www.isotc211.org/2005/gco}CharacterString_Impl" minOccurs="0"/>
* <element name="code" type="{http://www.isotc211.org/2005/gco}CharacterString_Impl" minOccurs="0"/>
* <element name="isAbstract" type="{http://www.isotc211.org/2005/gco}Boolean_Impl"/>
* <element name="aliases" type="{http://www.isotc211.org/2005/gco}LocalName_Impl" maxOccurs="unbounded" minOccurs="0"/>
* <element name="inheritsFrom" type="{http://www.isotc211.org/2005/gfc}FC_InheritanceRelation_Impl" maxOccurs="unbounded" minOccurs="0"/>
* <element name="inheritsTo" type="{http://www.isotc211.org/2005/gfc}FC_InheritanceRelation_Impl" maxOccurs="unbounded" minOccurs="0"/>
* <element name="featureCatalogue" type="{http://www.isotc211.org/2005/gfc}FC_FeatureCatalogue_Impl"/>
* <element name="carrierOfCharacteristics" type="{http://www.isotc211.org/2005/gfc}FC_Impl_Impl" maxOccurs="unbounded" minOccurs="0"/>
* <element name="constrainedBy" type="{http://www.isotc211.org/2005/gfc}FC_Constraint_Impl" maxOccurs="unbounded" minOccurs="0"/>
* <element name="definitionReference" type="{http://www.isotc211.org/2005/gfc}FC_DefinitionReference_Impl" minOccurs="0"/>
* </sequence>
* </extension>
* </complexContent>
* </complexType>
* </pre>
*
*
* @module
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "FC_FeatureType_Type", propOrder = {
"typeName",
"definition",
"code",
"isAbstract",
"aliases",
"inheritsFrom",
"inheritsTo",
"featureCatalogue",
"carrierOfCharacteristics",
"constrainedBy",
"definitionReference"
})
@XmlSeeAlso({
FeatureAssociationImpl.class
})
@XmlRootElement(name = "FC_FeatureType")
public class FeatureTypeImpl implements FeatureType, Referenceable {
@XmlAttribute
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
@XmlID
@XmlSchemaType(name = "ID")
private String id;
@XmlJavaTypeAdapter(GO_GenericName.class)
@XmlElement(required = true)
private LocalName typeName;
private String definition;
private String code;
@XmlElement(required = true)
private Boolean isAbstract;
@XmlJavaTypeAdapter(GO_GenericName.class)
private List<LocalName> aliases;
private List<InheritanceRelation> inheritsFrom;
private List<InheritanceRelation> inheritsTo;
@XmlJavaTypeAdapter(FeatureCatalogueAdapter.class)
private FeatureCatalogue featureCatalogue;
private List<PropertyType> carrierOfCharacteristics;
private List<Constraint> constrainedBy;
private DefinitionReference definitionReference;
@XmlTransient
private boolean isReference = false;
@XmlTransient
protected boolean rootElement = true;
/**
* An empty constructor used by JAXB
*/
public FeatureTypeImpl() {
}
/**
* Clone a FeatureType
*/
public FeatureTypeImpl(final FeatureType feature) {
if (feature != null) {
this.aliases = feature.getAliases();
this.carrierOfCharacteristics = feature.getCarrierOfCharacteristics();
this.code = feature.getCode();
this.id = feature.getId();
this.constrainedBy = feature.getConstrainedBy();
this.definition = feature.getDefinition();
this.definitionReference = feature.getDefinitionReference();
this.featureCatalogue = feature.getFeatureCatalogue();
this.inheritsFrom = feature.getInheritsFrom();
this.inheritsTo = feature.getInheritsTo();
this.isAbstract = feature.getIsAbstract();
this.typeName = feature.getTypeName();
}
}
/**
* Build a new Feature type
*/
public FeatureTypeImpl(final String id, final LocalName typeName, final String definition, final String code, final Boolean isAbstract, final List<LocalName> aliases,
final FeatureCatalogue catalogue, final List<PropertyType> carrierOfCharacteristics) {
if (id != null) {
this.id = id;
} else {
this.id = "ftype-" + code;
}
this.aliases = aliases;
this.carrierOfCharacteristics = carrierOfCharacteristics;
this.code = code;
this.definition = definition;
this.featureCatalogue = catalogue;
this.isAbstract = isAbstract;
this.typeName = typeName;
}
/**
* Gets the value of the typeName property.
*/
public LocalName getTypeName() {
return typeName;
}
/**
* Sets the value of the typeName property.
*/
public void setTypeName(final LocalName value) {
this.typeName = value;
}
/**
* Gets the value of the definition property.
*
*/
public String getDefinition() {
return definition;
}
/**
* Sets the value of the definition property.
*/
public void setDefinition(final String value) {
this.definition = value;
}
/**
* Gets the value of the code property.
*
*/
public String getCode() {
return code;
}
/**
* Sets the value of the code property.
*/
public void setCode(final String value) {
this.code = value;
}
/**
* Gets the value of the isAbstract property.
*/
public Boolean getIsAbstract() {
return isAbstract;
}
/**
* Sets the value of the isAbstract property.
*/
public void setIsAbstract(final Boolean value) {
this.isAbstract = value;
}
/**
* Gets the value of the aliases property.
*
*/
public List<LocalName> getAliases() {
if (aliases == null) {
aliases = new ArrayList<LocalName>();
}
return aliases;
}
public void setAliases(final LocalName alias) {
if (aliases == null) {
aliases = new ArrayList<LocalName>();
}
this.aliases.add(alias);
}
public void setAliases(final List<LocalName> aliases) {
this.aliases = aliases;
}
/**
* Gets the value of the inheritsFrom property.
*/
public List<InheritanceRelation> getInheritsFrom() {
if (inheritsFrom == null) {
inheritsFrom = new ArrayList<InheritanceRelation>();
}
return this.inheritsFrom;
}
public void setInheritsFrom(final InheritanceRelation inheritsFrom) {
if (this.inheritsFrom == null) {
this.inheritsFrom = new ArrayList<InheritanceRelation>();
}
this.inheritsFrom.add(inheritsFrom);
}
public void setInheritsFrom(final List<InheritanceRelation> inheritsFrom) {
this.inheritsFrom = inheritsFrom;
}
/**
* Gets the value of the inheritsTo property.
*/
public List<InheritanceRelation> getInheritsTo() {
if (inheritsTo == null) {
inheritsTo = new ArrayList<InheritanceRelation>();
}
return this.inheritsTo;
}
public void setInheritsTo(final InheritanceRelation inheritsTo) {
if (this.inheritsTo == null) {
this.inheritsTo = new ArrayList<InheritanceRelation>();
}
this.inheritsTo.add(inheritsTo);
}
public void setInheritsTo(final List<InheritanceRelation> inheritsTo) {
this.inheritsTo = inheritsTo;
}
/**
* Gets the value of the featureCatalogue property.
*/
public FeatureCatalogue getFeatureCatalogue() {
return featureCatalogue;
}
/**
* Sets the value of the featureCatalogue property.
*/
public void setFeatureCatalogue(final FeatureCatalogue value) {
this.featureCatalogue = value;
}
/**
* Gets the value of the carrierOfCharacteristics property.
*
*/
public List<PropertyType> getCarrierOfCharacteristics() {
if (carrierOfCharacteristics == null) {
carrierOfCharacteristics = new ArrayList<PropertyType>();
}
return this.carrierOfCharacteristics;
}
public void setCarrierOfCharacteristics(final PropertyType carrierOfCharacteristics) {
if (this.carrierOfCharacteristics == null) {
this.carrierOfCharacteristics = new ArrayList<PropertyType>();
}
this.carrierOfCharacteristics.add(carrierOfCharacteristics);
}
public void setCarrierOfCharacteristics(final FeatureAttribute carrierOfCharacteristics) {
if (this.carrierOfCharacteristics == null) {
this.carrierOfCharacteristics = new ArrayList<PropertyType>();
}
this.carrierOfCharacteristics.add(carrierOfCharacteristics);
}
public void setCarrierOfCharacteristics(final List<PropertyType> carrierOfCharacteristics) {
this.carrierOfCharacteristics = carrierOfCharacteristics;
}
/**
* Gets the value of the constrainedBy property.
*
*/
public List<Constraint> getConstrainedBy() {
if (constrainedBy == null) {
constrainedBy = new ArrayList<Constraint>();
}
return this.constrainedBy;
}
public void setConstrainedBy(final Constraint constrainedBy) {
if (this.constrainedBy == null) {
this.constrainedBy = new ArrayList<Constraint>();
}
this.constrainedBy.add(constrainedBy);
}
public void setConstrainedBy(final List<Constraint> constrainedBy) {
this.constrainedBy = constrainedBy;
}
/**
* Gets the value of the definitionReference property.
*
*/
public DefinitionReference getDefinitionReference() {
return definitionReference;
}
/**
* Sets the value of the definitionReference property.
*
*/
public void setDefinitionReference(final DefinitionReference value) {
this.definitionReference = value;
}
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
/**
* set the feature in reference mode
*/
public void setReference(final boolean mode) {
this.isReference = mode;
}
/**
* get the current feature in reference mode
*/
public boolean isReference() {
return isReference;
}
public FeatureTypeImpl getReference() {
FeatureTypeImpl reference = new FeatureTypeImpl(this);
reference.setReference(true);
return reference;
}
/**
* This java object contains cycle. this cycle cannot be handle by JAXB.
* We must create reference mark in the xml.
* @param marshaller
*/
private void beforeMarshal(final Marshaller marshaller) {
if (rootElement) {
beforeMarshal(new HashMap<String, Referenceable>());
}
}
public Map<String, Referenceable> beforeMarshal(Map<String, Referenceable> alreadySee) {
if (id != null && !id.isEmpty()) {
alreadySee.put(id, this);
}
rootElement = false;
List<InheritanceRelation> fromReplacement = new ArrayList<InheritanceRelation>();
for (InheritanceRelation in: getInheritsFrom()) {
InheritanceRelationImpl inf = (InheritanceRelationImpl) in;
if (alreadySee.get(inf.getId()) != null) {
fromReplacement.add(inf.getReference());
} else {
alreadySee = inf.beforeMarshal(alreadySee);
fromReplacement.add(inf);
}
}
inheritsFrom = fromReplacement;
List<InheritanceRelation> toReplacement = new ArrayList<InheritanceRelation>();
for (InheritanceRelation in: getInheritsTo()) {
InheritanceRelationImpl inf = (InheritanceRelationImpl) in;
if (alreadySee.get(inf.getId()) != null) {
toReplacement.add(inf.getReference());
} else {
alreadySee = inf.beforeMarshal(alreadySee);
toReplacement.add(inf);
}
}
inheritsTo = toReplacement;
if (featureCatalogue != null) {
if (alreadySee.get(featureCatalogue.getId()) != null) {
featureCatalogue = ((FeatureCatalogueImpl)featureCatalogue).getReference();
} else {
alreadySee = ((FeatureCatalogueImpl)featureCatalogue).beforeMarshal(alreadySee);
}
}
List<PropertyType> replacement = new ArrayList<PropertyType>();
for (PropertyType f: getCarrierOfCharacteristics()) {
PropertyTypeImpl p = (PropertyTypeImpl) f;
if (alreadySee.get(p.getId()) != null) {
replacement.add(p.getReference());
} else {
alreadySee = p.beforeMarshal(alreadySee);
replacement.add(p);
}
}
carrierOfCharacteristics = replacement;
return alreadySee;
}
@Override
public String toString() {
StringBuilder s = new StringBuilder("[").append(this.getClass().getSimpleName()).append("]:").append('\n');
s.append("id: ").append(id).append('\n');
if (isReference) {
s.append("reference mode").append('\n');
} else {
if (typeName != null) {
s.append("typeName: ").append(typeName).append('\n');
}
if (definition != null) {
s.append("definition: ").append(definition).append('\n');
}
if (code != null) {
s.append("code: ").append(code).append('\n');
}
if (isAbstract != null) {
s.append("isAbstract: ").append(isAbstract).append('\n');
}
if (aliases != null) {
s.append("aliases: ").append('\n');
for (LocalName l: aliases) {
s.append(l).append('\n');
}
}
if (inheritsFrom != null) {
s.append("inherits from: ").append('\n');
for (InheritanceRelation l: inheritsFrom) {
s.append(l).append('\n');
}
}
if (inheritsTo != null) {
s.append("inherits to: ").append('\n');
for (InheritanceRelation l: inheritsTo) {
s.append(l).append('\n');
}
}
if (featureCatalogue != null) {
s.append("featureCatalogue: ").append(featureCatalogue).append('\n');
}
if (carrierOfCharacteristics != null) {
setReference(true);
s.append("carrier of characteristics: ").append('\n');
for (PropertyType l: carrierOfCharacteristics) {
s.append(l).append('\n');
}
setReference(false);
}
if (constrainedBy != null) {
s.append("constained by: ").append('\n');
for (Constraint l: constrainedBy) {
s.append(l).append('\n');
}
}
if (definitionReference != null) {
s.append("definition reference: ").append(definitionReference).append('\n');
}
}
return s.toString();
}
/**
* Verify if this entry is identical to the specified object.
*/
@Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (object instanceof FeatureTypeImpl) {
final FeatureTypeImpl that = (FeatureTypeImpl) object;
//to avoid infinite cycle
boolean carrier = false;
carrier = Objects.equals(this.getCarrierOfCharacteristics().size(), that.getCarrierOfCharacteristics().size());
if (carrier) {
for (int i = 0; i < this.getCarrierOfCharacteristics().size(); i++) {
final String thisId = this.getCarrierOfCharacteristics().get(i).getId();
final String thatId = that.getCarrierOfCharacteristics().get(i).getId();
// if the ids are null we try the name
if (thisId == null && thatId == null) {
final LocalName thisName = this.getCarrierOfCharacteristics().get(i).getMemberName();
final LocalName thatName = that.getCarrierOfCharacteristics().get(i).getMemberName();
carrier = Objects.equals(thisName, thatName);
} else {
carrier = Objects.equals(thisId, thatId);
}
}
} else {
return false;
}
//to avoid infinite cycle
boolean catalogue = false;
if (this.featureCatalogue != null && that.featureCatalogue != null) {
catalogue = Objects.equals(this.featureCatalogue.getId(), that.featureCatalogue.getId());
} else if (this.featureCatalogue == null && that.featureCatalogue == null){
catalogue = true;
}
//to avoid infinite cycle
boolean inherits = Objects.equals(this.getInheritsFrom().size(), that.getInheritsFrom().size()) &&
Objects.equals(this.getInheritsTo().size(), that.getInheritsTo().size());
return Objects.equals(this.aliases, that.aliases) &&
Objects.equals(this.code, that.code) &&
Objects.equals(this.constrainedBy, that.constrainedBy) &&
Objects.equals(this.definition, that.definition) &&
Objects.equals(this.definitionReference, that.definitionReference) &&
Objects.equals(this.id, that.id) &&
Objects.equals(this.isAbstract, that.isAbstract) &&
Objects.equals(this.typeName, that.typeName) &&
inherits && catalogue && carrier;
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 61 * hash + (this.id != null ? this.id.hashCode() : 0);
hash = 61 * hash + (this.typeName != null ? this.typeName.hashCode() : 0);
hash = 61 * hash + (this.code != null ? this.code.hashCode() : 0);
return hash;
}
}