package org.geotools.data.efeature; import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EAttribute; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EPackage; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.BasicExtendedMetaData; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.ExtendedMetaData; import org.eclipse.emf.query.conditions.eobjects.EObjectCondition; import org.eclipse.emf.query.statements.WHERE; import org.geotools.data.Transaction; import org.geotools.data.efeature.internal.EFeatureContextHelper; import org.geotools.data.efeature.internal.EFeatureInternal; import org.geotools.data.efeature.query.EFeatureEncoderException; import org.geotools.data.efeature.query.EFeatureFilter; import org.geotools.data.efeature.query.EFeatureQuery; import org.geotools.data.efeature.query.EObjectConditionEncoder; import org.geotools.filter.identity.FeatureIdImpl; import org.opengis.feature.Feature; import org.opengis.feature.Property; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.filter.Filter; import org.opengis.filter.identity.Identifier; import com.vividsolutions.jts.geom.Geometry; /** * {@link EFeature} utility class. * <p> * * @author kengu * */ public class EFeatureUtils { /** * Check if at least one structure is available for instance construction. * <p> * * @return <code>true</code> if at least one structure is available for * instance construction. */ public static <T extends EStructureInfo<?>> boolean isAvailable(Map<String, T> eMap) { for (EStructureInfo<?> it : eMap.values()) { if (it.isAvailable()) return true; } return false; } /** * Create a {@link EFeature} status instance * * @param source - source which status apply * @param type - status type * @param message - (optional) message * @param cause - (optional) {@link Throwable thowable} or * {@link Throwable#getStackTrace() stack trace} cause * @return a new {@link EFeatureStatus} instance * @throws IllegalArgumentException If cause is not <code>null</code>, * and not a {@link Throwable} or {@link StackTraceElement} array. */ public static EFeatureStatus newStatus(final Object source, final int type, final String message, final Object cause) { if(!(cause instanceof Throwable || cause instanceof StackTraceElement[] || cause==null) ) { throw new IllegalArgumentException( "Cause can only be Throwable and StackTraceElement[]"); } return new EFeatureStatus() { @Override public int getType() { return type; } @Override public Object getSource() { return source; } @Override public String getMessage() { return message; } @Override public Throwable getCause() { return (cause instanceof Throwable ? (Throwable)cause : null); } @Override public StackTraceElement[] getStackTrace() { return (cause instanceof Throwable ? ((Throwable)cause).getStackTrace() : (StackTraceElement[])cause); } @Override public boolean isType(int match) { return type == match; } @Override public boolean isSuccess() { return isType(SUCCESS); } @Override public boolean isWarning() { return isType(WARNING); } @Override public boolean isFailure() { return isType(FAILURE); } @Override public EFeatureStatus clone(String message) { return newStatus(source, type, message, cause); } @Override public EFeatureStatus clone(String message, Object cause) { return newStatus(source, type, message, cause); } }; } /** * Check if given {@link EClassifier classifier} implements * {@link EFeature}, or contains {@link EFeature} compatible data. * @param eClassifier - the classifier to test for compatibility * @return <code>true</code> if compatible. */ public static boolean isCompatible(EClassifier eClassifier) { if(eClassifier instanceof EFeature) { return true; } else if(eClassifier instanceof EClass) { EClass eClass = (EClass)eClassifier; for(EAttribute it : eClass.getEAllAttributes()) { // // Contains geometry data? // if (Geometry.class.isAssignableFrom(it.getEAttributeType().getInstanceClass())) { return true; } } } return false; } /** * Get {@link EFeature} folder name from {@link SimpleFeatureType} name * <p> * {@link SimpleFeatureType} names have the following * * <pre> * eType=<eFolder>.<eFeature> * * where * * eFolder = {@link EFeature} folder name * eFeature = {@link EFeature} class | reference name * </pre> * * @param eType - given {@link SimpleFeatureType} name * @return a {@link EFeature} folder name if {@link #isSimpleFeatureType(String)}, * <code>null</code> otherwise. */ public static String toFolderName(String eType) { if (!(eType == null || eType.length() == 0)) { int i = eType.indexOf("."); return (i == -1 ? eType : eType.substring(0, i)); } return null; } /** * Get {@link EFeature} name from {@link SimpleFeatureType} name * <p> * {@link SimpleFeatureType} names have the following * * <pre> * eType=<eFolder>.<eFeature> * * where * * eFolder = {@link EFeature} folder name * eFeature = {@link EFeature} class | reference name * </pre> * * @param eType - given {@link SimpleFeatureType} name * @return a {@link EFeature} name if {@link #isSimpleFeatureType(String)}, <code>null</code> * otherwise. */ public static String toFeatureName(String eType) { if (!(eType == null || eType.length() == 0)) { int i = eType.indexOf("."); if (i != -1) { return eType.substring(i + 1); } } return null; } /** * Check if given {@link EClass} extends given super type * * @param eClass - given {@link EClass} instance * @param eName - super {@link EClass} name * @return <code>true</code> if super {@link EClass} is implemented by given {@link EClass}. */ public static boolean isInstanceOf(EClass eClass, String eName) { for (EClass it : eClass.getEAllSuperTypes()) { if (it.getName() == eName) { return true; } } return false; } /** * Get {@link EPackage} instance from namespace URI. * * @param eResource - {@link EPackage} instance * @param eNsURI - namespace URI string * @return a {@link EPackage} instance if found, <code>null</code> otherwise. */ public static EPackage ePackage(Resource eResource, String eNsURI) { EPackage.Registry r = eResource.getResourceSet().getPackageRegistry(); return r.getEPackage(eNsURI); } /** * Get named {@link EReference} in given class * * @param eClass - {@link EClass} instance * @return a {@link EReference} instance if found, <code>null</code> otherwise */ public static EReference eGetReference(EClass eClass, String eName) { if (eClass != null) { for (EReference it : eClass.getEAllReferences()) { if (it.getName() == eName) { return it; } } } return null; } /** * Get named {@link EAttribute} {@link Map} for given class * * @param eClass - {@link EClass} instance * @return a named {@link EAttribute} {@link Map} */ public static Map<String, EAttribute> eGetAttributeMap(EClass eClass) { Map<String, EAttribute> map = new HashMap<String, EAttribute>(); if (eClass != null) { return eGetAttributeMap(eClass.getEAllAttributes()); } return map; } /** * Get named {@link EAttribute} in given class * * @param eClass - {@link EClass} instance * @return a {@link EAttribute} instance if found, <code>null</code> otherwise */ public static EAttribute eGetAttribute(EClass eClass, String eName) { if (eClass != null) { for (EAttribute it : eClass.getEAllAttributes()) { if (it.getName() == eName) { return it; } } } return null; } public static Map<String, EAttribute> eGetAttributeMap(EList<EAttribute> list) { Map<String, EAttribute> map = new HashMap<String, EAttribute>(); if (list != null) { for (EAttribute it : list) { map.put(it.getName(), it); } } return map; } /** * Get an {@link EStructuralFeature} in given object with given name if exists * * @param eObject - {@link EObject} instance * @param eName - feature name * @return an {@link EStructuralFeature} instance if found, null otherwise. */ public static EStructuralFeature eGetStructuralFeature(EObject eObject, String eName, String eNsURI) { EPackage.Registry eRegistry = eObject.eResource().getResourceSet().getPackageRegistry(); return eGetStructuralFeature(eRegistry, eObject.eClass(), eName, eNsURI); } /** * Get an {@link EStructuralFeature} in given object with given name if exists * * @param eClass - {@link EClass} instance * @param eName - element name * @param eNsURI - package name space URI specification * @return an {@link EStructuralFeature} instance if found, null otherwise. */ public static EStructuralFeature eGetStructuralFeature(EPackage.Registry eRegistry, EClass eClass, String eName, String eNsURI) { ExtendedMetaData data = new BasicExtendedMetaData(eRegistry) { @Override protected boolean isFeatureKindSpecific() { return false; } @Override protected boolean isFeatureNamespaceMatchingLax() { return true; } }; return data.getAttribute(eClass, eNsURI, eName); } /** * Get {@link EObject} {@link URI} in containing {@link Resource} instance * <p> * * @param eObject - {@link EObject} instance * @return a {@link URI} instance * @see {@link EcoreUtil.getURI} */ public static URI eGetObjectURI(EObject eObject) { return EcoreUtil.getURI(eObject); } /** * Create new {@link EObjectCondition} on {@link EClass} instance. * <p> * Only {@link EObject}s of given {@link EClass} will satisfy this filter. * * @param eClass - given {@link EClass} instance * @return a {@link EObjectCondition} instance. */ public static EObjectCondition createEClassFilter(final EClass eClass) { return new EObjectCondition() { @Override public boolean isSatisfied(EObject eObject) { boolean bFlag = eClass.isInstance(eObject); return bFlag; } }; } /** * Convert given GeoTools {@link Filter} to a {@link EFeatureQuery} statement * capable of querying {@link EObject} instances from all {@link EClass}es that * extends the {@link EFeaturePackage#getEFeature() EFeature class}. * * @param featureType - {@link SimpleFeatureType} instance * @param eObjects - {@link TreeIterator} to by queried * @param filter - GeoTools {@link Filter filter} instance * @return a {@link EFeatureQuery} statement * @throws EFeatureEncoderException If filter encoding failed. */ public static EFeatureQuery toEFeatureQuery( TreeIterator<EObject> eObjects, Filter filter) throws EFeatureEncoderException { // // Get prototype structure from internal context // EFeatureInfo eInfo = EFeatureContextHelper.ePrototype(EFeaturePackage.eINSTANCE.getEFeature()); // // Forward // return toEFeatureQuery(eInfo,eObjects, filter); } /** * Convert GeoTools {@link Filter} to a {@link EFeatureQuery} statement * capable of querying {@link EObject} instances from the {@link EClass} * defined by given {@link EFeatureInfo structure}. * * @param eFeatureInfo - filter on {@link EFeatureInfo} instance * @param featureType - {@link SimpleFeatureType} instance * @param eObjects - {@link TreeIterator} to by queried * @param filter - GeoTools {@link Filter filter} instance * @return a {@link EFeatureQuery} statement * @throws EFeatureEncoderException If filter encoding failed. */ public static EFeatureQuery toEFeatureQuery(EFeatureInfo eFeatureInfo, TreeIterator<EObject> eObjects, Filter filter) throws EFeatureEncoderException { // // Do sanity checks // isSane("eFeatureInfo",eFeatureInfo); isSane("eObjects",eObjects); isSane("filter",filter); // // Create an EClass filter // EObjectCondition eClassFilter = createEClassFilter(eFeatureInfo.eClass()); // // Create spatial filter // EObjectCondition eSpatialFilter = toEObjectCondition(eFeatureInfo, true, filter); // // Create EMF Query WHERE clause // WHERE where = new WHERE(eClassFilter.AND(eSpatialFilter)); // // Create EFeature filter // EFeatureFilter eWhere = new EFeatureFilter(where); // // Create query instance // return new EFeatureQuery(eObjects, eWhere); } public static EObjectCondition toEObjectCondition( EFeatureInfo eFeatureInfo, boolean looseBBox, Filter filter) throws EFeatureEncoderException { // // Create encoder instance // EObjectConditionEncoder encoder = new EObjectConditionEncoder(eFeatureInfo, looseBBox); // // Encode filter // return encoder.encode(filter); } public static String eGetNsURI(EObject eObject, boolean container) { if(eObject instanceof EClass) { return eGetNsURI((EClass)eObject); } else if(eObject instanceof EReference) { return eGetNsURI((EReference)eObject,container); } return eGetNsURI(eObject.eClass()); } public static String eGetNsURI(EClass eClass) { return eClass.getEPackage().getNsURI(); } public static String eGetNsURI(EReference eReference, boolean container) { EClass eClass = (container ? eReference.eContainer().eClass() : eReference.eClass()); return eClass.getEPackage().getNsURI(); } public static EClass eGetContainingClass(EObject eChild) { EReference eReference = (eChild != null ? eChild.eContainmentFeature() : null); return (eReference != null ? eReference.getEContainingClass() : null); } public static StackTraceElement getStackTraceElement(int index, int remove) { StackTraceElement[] stack = getStackTrace(remove+1); return stack[index]; } public static StackTraceElement[] getStackTrace(int remove) { Throwable t = new Throwable(); t.fillInStackTrace(); StackTraceElement[] stack = t.getStackTrace(); StackTraceElement[] current = new StackTraceElement[stack.length-remove-1]; System.arraycopy(stack, remove+1, current, 0, stack.length-remove-1); return current; } public static String getEnclosingMethodName() { Throwable t = new Throwable(); t.fillInStackTrace(); StackTraceElement[] stack = t.getStackTrace(); return stack[stack.length-2].getMethodName(); } public static void isSane(String name, Object object) { if(object==null) { throw new NullPointerException(name + " can not be null"); } } public static <T> T[] concat(Class<T> type, T[]... arrays) { int count = 0; for(T[] it : arrays) count += it.length; @SuppressWarnings("unchecked") T[] m = (T[])Array.newInstance(type, count); if(count>0) { count = 0; for(T[] it : arrays) { System.arraycopy(it, 0, m, count, it.length); count += it.length; } } return m; } public static Set<Identifier> toEIDs(Object...eIDs){ Set<Identifier> eIDSet = new HashSet<Identifier>(eIDs.length); for(Object eID : eIDs) { eIDSet.add(new FeatureIdImpl(eID.toString())); } return eIDSet; } /** * Get {@link ESimpleFeature} values in immutable order. * </p> * @param eStructure * @param eObject * @param transaction * @return a ordered list of a{@link ESimpleFeature} values */ public static List<Object> eGetFeatureValues( EFeatureInfo eStructure, EObject eObject, Transaction transaction) { // // Get internal EFeature implementation // EFeatureInternal eInternal = EFeatureInternal.eInternal(eStructure, eObject); // // Enter modification mode // eInternal.enter(transaction); // // Try to get values // try { List<Object> eList = new ArrayList<Object>(); for(EAttribute it : eStructure.eGetAttributeList(true)) { eList.add(eObject.eGet(it)); } return Collections.unmodifiableList(eList); } finally { // // Leave modification mode // eInternal.leave(); } } /** * Set {@link ESimpleFeature} values in immutable order. * </p> * @param eStructure * @param eObject * @param eValues */ public static void eSetFeatureValues( EFeatureInfo eStructure, EObject eObject, List<Object> eValues, Transaction transaction) { // // Get internal EFeature implementation // EFeatureInternal eInternal = EFeatureInternal.eInternal(eStructure, eObject); // // Enter modification mode // eInternal.enter(transaction); // // Try to set values // try { int i=0; for(EAttribute it : eStructure.eGetAttributeList(true)) { eObject.eSet(it,eValues.get(i++)); } } finally { // // Leave modification mode // eInternal.leave(); } } /** * Convert Feature to list of values * @param feature * @return a list of feature values */ public static List<Object> toFeatureValues(Feature feature) { Collection<Property> properties = feature.getProperties(); List<Object> values = new ArrayList<Object>(properties.size()); for(Property it : feature.getProperties()) { values.add(it.getValue()); } return values; } public final static <K,V> Map<K,V> newMap(int...sizes) { int size = 0; for(int it : sizes) size += it; return new HashMap<K, V>(size); } public final static <K,V> Map<K,V> newMap(Map<K,V> fromMap, int...sizes) { int size = fromMap.size(); for(int it : sizes) size += it; return newMap(size); } public final static <V> List<V> newList(int...sizes) { int size = 0; for(int it : sizes) size += it; return new ArrayList<V>(size); } public final static <V> List<V> newList(List<V> fromList, int...sizes) { int size = fromList.size(); for(int it : sizes) size += it; return newList(size); } }