/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, 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.filter.expression;
import java.util.regex.Pattern;
import org.geotools.factory.Hints;
import org.geotools.feature.IllegalAttributeException;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.GeometryDescriptor;
import com.vividsolutions.jts.geom.Geometry;
/**
* Creates a property accessor for simple features.
* <p>
* The created accessor handles a small subset of xpath expressions, a
* non-nested "name" which corresponds to a feature attribute, and "@id",
* corresponding to the feature id.
* </p>
* <p>
* THe property accessor may be run against {@link SimpleFeature}, or
* against {@link SimpleFeature}. In the former case the feature property
* value is returned, in the latter the feature property type is returned.
* </p>
*
* @author Justin Deoliveira, The Open Planning Project
*
*
*
* @source $URL$
*/
public class SimpleFeaturePropertyAccessorFactory implements
PropertyAccessorFactory {
/** Single instnace is fine - we are not stateful */
static PropertyAccessor ATTRIBUTE_ACCESS = new SimpleFeaturePropertyAccessor();
static PropertyAccessor DEFAULT_GEOMETRY_ACCESS = new DefaultGeometrySimpleFeaturePropertyAccessor();
static PropertyAccessor FID_ACCESS = new FidSimpleFeaturePropertyAccessor();
static Pattern idPattern = Pattern.compile("@(\\w+:)?id");
static Pattern propertyPattern = Pattern.compile("(\\w+:)?(\\w+)");
public PropertyAccessor createPropertyAccessor(Class type, String xpath,
Class target, Hints hints) {
if ( xpath == null )
return null;
if (!SimpleFeature.class.isAssignableFrom(type) && !SimpleFeatureType.class.isAssignableFrom(type))
return null; // we only work with simple feature
//if ("".equals(xpath) && target == Geometry.class)
if ("".equals(xpath))
return DEFAULT_GEOMETRY_ACCESS;
//check for fid access
if (idPattern.matcher(xpath).matches())
return FID_ACCESS;
//check for simple property acess
if (propertyPattern.matcher(xpath).matches()) {
return ATTRIBUTE_ACCESS;
}
return null;
}
/**
* We strip off namespace prefix, we need new feature model to do this
* property
* <ul>
* <li>BEFORE: foo:bar
* <li>AFTER: bar
* </ul>
*
* @param xpath
* @return xpath with any XML prefixes removed
*/
static String stripPrefix(String xpath) {
int split = xpath.indexOf(":");
if (split != -1) {
return xpath.substring(split + 1);
}
return xpath;
}
/**
* Access to SimpleFeature Identifier.
*
* @author Jody Garnett, Refractions Research Inc.
*/
static class FidSimpleFeaturePropertyAccessor implements PropertyAccessor {
public boolean canHandle(Object object, String xpath, Class target) {
//we only work against feature, not feature type
return object instanceof SimpleFeature && xpath.matches("@(\\w+:)?id");
}
public Object get(Object object, String xpath, Class target) {
SimpleFeature feature = (SimpleFeature) object;
return feature.getID();
}
public void set(Object object, String xpath, Object value, Class target)
throws IllegalAttributeException {
throw new IllegalAttributeException("feature id is immutable");
}
}
static class DefaultGeometrySimpleFeaturePropertyAccessor implements PropertyAccessor {
public boolean canHandle(Object object, String xpath, Class target) {
if ( !"".equals( xpath ) )
return false;
// if ( target != Geometry.class )
// return false;
if ( !( object instanceof SimpleFeature || object instanceof SimpleFeatureType ) ) {
return false;
}
return true;
}
public Object get(Object object, String xpath, Class target) {
if ( object instanceof SimpleFeature ) {
SimpleFeature f = (SimpleFeature) object;
Object defaultGeometry = f.getDefaultGeometry();
// not found? Ok, let's do a lookup then...
if ( defaultGeometry == null ) {
for ( Object o : f.getAttributes() ) {
if ( o instanceof Geometry ) {
defaultGeometry = o;
break;
}
}
}
return defaultGeometry;
}
if ( object instanceof SimpleFeatureType ) {
SimpleFeatureType ft = (SimpleFeatureType) object;
GeometryDescriptor gd = ft.getGeometryDescriptor();
if ( gd == null ) {
//look for any geometry descriptor
for ( AttributeDescriptor ad : ft.getAttributeDescriptors() ) {
if ( Geometry.class.isAssignableFrom( ad.getType().getBinding() ) ) {
return ad;
}
}
}
return gd;
}
return null;
}
public void set(Object object, String xpath, Object value, Class target)
throws IllegalAttributeException {
if ( object instanceof SimpleFeature ) {
((SimpleFeature) object).setDefaultGeometry( (Geometry) value );
}
if ( object instanceof SimpleFeatureType ) {
throw new IllegalAttributeException("feature type is immutable");
}
}
}
static class SimpleFeaturePropertyAccessor implements PropertyAccessor {
public boolean canHandle(Object object, String xpath, Class target) {
xpath = stripPrefix(xpath);
if ( object instanceof SimpleFeature ) {
return ((SimpleFeature) object).getType().getDescriptor(xpath) != null;
}
if ( object instanceof SimpleFeatureType ) {
return ((SimpleFeatureType) object).getDescriptor( xpath ) != null;
}
return false;
}
public Object get(Object object, String xpath, Class target) {
xpath = stripPrefix(xpath);
if ( object instanceof SimpleFeature ) {
return ((SimpleFeature) object).getAttribute( xpath );
}
if ( object instanceof SimpleFeatureType ) {
return ((SimpleFeatureType) object).getDescriptor( xpath );
}
return null;
}
public void set(Object object, String xpath, Object value, Class target)
throws IllegalAttributeException {
xpath = stripPrefix(xpath);
if ( object instanceof SimpleFeature ) {
((SimpleFeature) object).setAttribute( xpath, value );
}
if ( object instanceof SimpleFeatureType ) {
throw new IllegalAttributeException("feature type is immutable");
}
}
}
}