package org.geotools.data.efeature;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.emf.ecore.EAttribute;
import org.geotools.data.efeature.internal.EFeatureVoidIDFactory;
import org.geotools.feature.IllegalAttributeException;
import org.geotools.feature.NameImpl;
import org.geotools.feature.type.AttributeTypeImpl;
import org.geotools.feature.type.Types;
import org.opengis.feature.Attribute;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.AttributeType;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
/**
*
* @author kengu
*
*/
@SuppressWarnings("deprecation")
public class EFeatureAttributeInfo extends EStructureInfo<EFeatureInfo> {
protected String eName;
protected String eNsURI;
protected String eFolderName;
protected String eFeatureName;
protected boolean eIsID;
protected WeakReference<EAttribute> eAttribute;
protected Map<Object, Object> userData;
private AttributeDescriptorDelegate eDescriptor;
// -----------------------------------------------------
// Constructors
// -----------------------------------------------------
/**
* Default constructor
*/
protected EFeatureAttributeInfo() { /*NOP*/ }
/**
* Structure copy constructor.
* <p>
* This method copies the structure into given context.
* </p>
* <b>NOTE</b>: This method only adds a one-way reference from
* copied instance to given {@link EFeatureContext context}.
* No reference is added from the context to this attribute.
* </p>
* @param eAttributeInfo - copy from this {@link EFeatureAttributeInfo} instance
* @param eFeatureInfo - copy into this structure
*/
protected EFeatureAttributeInfo(EFeatureAttributeInfo eAttributeInfo, EFeatureInfo eFeatureInfo) {
//
// Forward (copies context, state and hints)
//
super(eAttributeInfo, eFeatureInfo);
//
// Copy context path
//
this.eNsURI = eAttributeInfo.eNsURI;
this.eFolderName = eAttributeInfo.eFolderName;
this.eFeatureName = eAttributeInfo.eName();
//
// Copy attribute
//
this.eName = eAttributeInfo.eName;
this.eAttribute = new WeakReference<EAttribute>(eAttributeInfo.eAttribute());
//
// Copy other attributes
//
this.eIsID = eAttributeInfo.eIsID;
this.isAvailable = eAttributeInfo.isAvailable;
}
// -----------------------------------------------------
// EFeatureAttribute methods
// -----------------------------------------------------
public boolean isID() {
return eIsID;
}
public String eName() {
return eName;
}
public String eNsURI() {
return eNsURI;
}
public String eFolderName() {
return eFolderName;
}
public String eFeatureName() {
return eFeatureName;
}
@Override
protected EFeatureInfo eParentInfo(boolean checkIsValid) {
//
// Get EFeatureContext structure
//
EFeatureContextInfo eContextInfo = eContext(checkIsValid).eStructure();
//
// Try complete structure first
//
EFeaturePackageInfo ePackageInfo = eContextInfo.
eGetPackageInfo(eNsURI);
//
// Full structure exists?
//
if(ePackageInfo!=null) {
return ePackageInfo.
eGetFolderInfo(eFolderName).
eGetFeatureInfo(eFeatureName);
}
//
// No it dosn't, try EFeature cache
//
return eContextInfo.eFeatureInfoCache().get(eNsURI, eFolderName, eFeatureName);
}
public EAttribute eAttribute() {
return eAttribute!=null ? eAttribute.get() : null;
}
public AttributeDescriptor getDescriptor() {
if (isAvailable() && eDescriptor == null) {
eDescriptor = new AttributeDescriptorDelegate();
}
return eDescriptor;
}
public EFeatureStatus validate(boolean isID, EAttribute eAttribute) {
//
// Invalidate structure
//
doInvalidate(false);
//
// 1) Verify that reference information exist
//
if (this.eName == null) {
return failure(this, eName(), "Attribute mismatch: EAttribute name not specified");
}
//
// 2) Verify attribute name
//
String eName = eAttribute.getName();
if (!this.eName.equals(eName)) {
return failure(this, eName(), "Attribute mismatch: Found + " + eName + ", expected " + this.eName);
}
//
// Get feature structure
//
EFeatureInfo eInfo = eParentInfo(false);
//
// 3) Verify that the EFeatureID factory instance create IDs for given attribute?
//
//
if(isID && eInfo!=null) {
//
// Get EFeatureIDFactory instance
//
EFeatureIDFactory eFactory = eContext(false).eIDFactory();
//
// Verify that the EFeatureID factory instance exists and
// creates IDs for this attribute
//
if(eFactory==null) {
return failure(this, eName(), "Attribute mismatch: " +
"No EFeatureIDFactory found");
}
else if(!(eFactory instanceof EFeatureVoidIDFactory || eFactory.creates(eAttribute))) {
return failure(this, eName(), "Attribute mismatch: " +
"EFeatureIDFactory does not create IDs for attribute " + eName);
}
}
//
// Set valid state
//
this.eIsID = isID;
// Confirm that structure is valid
//
return structureIsValid(eName());
}
/**
* Validate attribute against this structure.
*
* @param attribute - attribute to be validated
* @return <code>true</code> if valid.
*/
public EFeatureStatus validate(Attribute attribute) {
// TODO: Better validation against information
if (!getDescriptor().equals(attribute.getDescriptor())) {
return attributeIsInvalid();
}
// Confirm that attribute is valid
//
return attributeIsValid();
}
/**
* Validate {@link Property#getValue() attribute value} against this structure.
*
* @param value - attribute value to be validated
* @return <code>true</code> if valid.
*/
public EFeatureStatus validate(Object value) {
try {
// Validate value type
//
Types.validate(getDescriptor(), value);
} catch (IllegalAttributeException e) {
return valueIsInvalid(e);
}
// Confirm that attribute value is valid
//
return valueIsValid();
}
// -----------------------------------------------------
// EStructureInfo implementation
// -----------------------------------------------------
@Override
protected void doInvalidate(boolean deep) {
this.eIsID = false;
}
@Override
protected void doDispose() {
userData.clear();
userData = null;
eAttribute = null;
eDescriptor = null;
}
// -----------------------------------------------------
// AttributeDescriptor implementation
// -----------------------------------------------------
protected class AttributeDescriptorDelegate implements AttributeDescriptor {
private AttributeType attributeType;
@Override
public Name getName() {
return new NameImpl(eName);
}
@Override
public int getMinOccurs() {
return eAttribute == null ? -1 : limit(eAttribute().getLowerBound());
}
@Override
public int getMaxOccurs() {
return eAttribute == null ? -1 : limit(eAttribute().getUpperBound());
}
@Override
public boolean isNillable() {
return eAttribute == null ? false : !eAttribute().isRequired();
}
@Override
public Map<Object, Object> getUserData() {
if (userData == null) {
userData = new HashMap<Object, Object>();
}
return userData;
}
@Override
public AttributeType getType() {
if (isAvailable() && attributeType == null) {
//
// Get value instance class
//
final Class<?> cls = eAttribute().getEAttributeType().getInstanceClass();
//
// Create anonymous attribute type implementation
//
attributeType = new AttributeTypeImpl(getName(), cls, eIsID, false,
Collections.<Filter> emptyList(), null, null) {
@Override
public Object parse(Object value) throws IllegalArgumentException {
return DataBuilder.parse(cls, value);
}
};
}
return attributeType;
}
@Override
public String getLocalName() {
return getName().getLocalPart();
}
@Override
public Object getDefaultValue() {
return null;
}
}
// -----------------------------------------------------
// Object methods
// -----------------------------------------------------
@Override
public String toString() {
return getClass().getSimpleName() + "[" + eName + "]";
}
// -----------------------------------------------------
// Helper methods
// -----------------------------------------------------
/**
* Create {@link EFeatureAttributeInfo} from given {@link EAttribute}
* @param eFactory
* @param eContextID
* @param isID
* @param eAttribute
* @return
*/
protected static EFeatureAttributeInfo create(
EFeatureInfo eFeatureInfo, boolean isID, EAttribute eAttribute) {
//
// Create new instance
//
EFeatureAttributeInfo eInfo = new EFeatureAttributeInfo();
//
// Set construction hints
//
eInfo.eHints = eFeatureInfo.eHints;
//
// Set context
//
eInfo.eFactory = eFeatureInfo.eFactory;
eInfo.eContext = eFeatureInfo.eContext;
eInfo.eContextID = eFeatureInfo.eContextID;
//
// Set context path
//
eInfo.eNsURI = eFeatureInfo.eNsURI;
eInfo.eFolderName = eFeatureInfo.eFolderName;
eInfo.eFeatureName = eFeatureInfo.eName();
//
// Set other members
//
eInfo.eIsID = isID;
eInfo.eName = eAttribute.getName();
eInfo.eAttribute = new WeakReference<EAttribute>(eAttribute);
//
// Finished
//
return eInfo;
}
protected static int limit(int value) {
return value > 0 ? value : -1;
}
protected final EFeatureStatus attributeIsValid() {
StackTraceElement trace = EFeatureUtils.getStackTraceElement(0,1);
return success("Attribute is valid: "
+ trace.getClassName()+ "[" + eName() + "]#" + trace.getMethodName());
}
protected final EFeatureStatus attributeIsInvalid() {
StackTraceElement trace = EFeatureUtils.getStackTraceElement(0,1);
return failure(this, eName(), "Attribute is invalid: "
+ trace.getClassName()+ "[" + eName() + "]#" + trace.getMethodName());
}
protected final EFeatureStatus valueIsValid() {
StackTraceElement trace = EFeatureUtils.getStackTraceElement(0,1);
return success("Attribute value is valid: "
+ trace.getClassName()+ "[" + eName() + "]#" + trace.getMethodName());
}
protected final EFeatureStatus valueIsInvalid(Throwable cause) {
StackTraceElement trace = EFeatureUtils.getStackTraceElement(0,1);
return failure(this, eName(), "Attribute value is invalid: "
+ trace.getClassName()+ "[" + eName() + "]#" + trace.getMethodName());
}
}