001: package org.geotools.filter.expression;
002:
003: import java.util.regex.Pattern;
004:
005: import org.geotools.factory.Hints;
006: import org.geotools.feature.Feature;
007: import org.geotools.feature.FeatureType;
008: import org.geotools.feature.IllegalAttributeException;
009:
010: import com.vividsolutions.jts.geom.Geometry;
011:
012: /**
013: * Creates a property accessor for simple features.
014: * <p>
015: * The created accessor handles a small subset of xpath expressions, a
016: * non-nested "name" which corresponds to a feature attribute, and "@id",
017: * corresponding to the feature id.
018: * </p>
019: * <p>
020: * THe property accessor may be run against {@link org.geotools.feature.Feature}, or
021: * against {@link org.geotools.feature.FeatureType}. In the former case the feature property
022: * value is returned, in the latter the feature property type is returned.
023: * </p>
024: *
025: * @author Justin Deoliveira, The Open Planning Project
026: *
027: */
028: public class SimpleFeaturePropertyAccessorFactory implements
029: PropertyAccessorFactory {
030:
031: /** Single instnace is fine - we are not stateful */
032: static PropertyAccessor ATTRIBUTE_ACCESS = new SimpleFeaturePropertyAccessor();
033: static PropertyAccessor DEFAULT_GEOMETRY_ACCESS = new DefaultGeometrySimpleFeaturePropertyAccessor();
034: static PropertyAccessor FID_ACCESS = new FidSimpleFeaturePropertyAccessor();
035: static Pattern idPattern = Pattern.compile("@(\\w+:)?id");
036: static Pattern propertyPattern = Pattern.compile("(\\w+:)?(\\w+)");
037:
038: public PropertyAccessor createPropertyAccessor(Class type,
039: String xpath, Class target, Hints hints) {
040:
041: if (xpath == null)
042: return null;
043:
044: if (!Feature.class.isAssignableFrom(type)
045: && !FeatureType.class.isAssignableFrom(type))
046: return null; // we only work with simple feature
047:
048: //if ("".equals(xpath) && target == Geometry.class)
049: if ("".equals(xpath))
050: return DEFAULT_GEOMETRY_ACCESS;
051:
052: //check for fid access
053: if (idPattern.matcher(xpath).matches())
054: return FID_ACCESS;
055:
056: //check for simple property acess
057: if (propertyPattern.matcher(xpath).matches()) {
058: return ATTRIBUTE_ACCESS;
059: }
060:
061: return null;
062: }
063:
064: /**
065: * We strip off namespace prefix, we need new feature model to do this
066: * property
067: * <ul>
068: * <li>BEFORE: foo:bar
069: * <li>AFTER: bar
070: * </ul>
071: *
072: * @param xpath
073: * @return xpath with any XML prefixes removed
074: */
075: static String stripPrefix(String xpath) {
076: int split = xpath.indexOf(":");
077: if (split != -1) {
078: return xpath.substring(split + 1);
079: }
080: return xpath;
081: }
082:
083: /**
084: * Access to Feature Identifier.
085: *
086: * @author Jody Garnett, Refractions Research Inc.
087: */
088: static class FidSimpleFeaturePropertyAccessor implements
089: PropertyAccessor {
090: public boolean canHandle(Object object, String xpath,
091: Class target) {
092: //we only work against feature, not feature type
093: return object instanceof Feature
094: && xpath.matches("@(\\w+:)?id");
095: }
096:
097: public Object get(Object object, String xpath, Class target) {
098: Feature feature = (Feature) object;
099: return feature.getID();
100: }
101:
102: public void set(Object object, String xpath, Object value,
103: Class target) throws IllegalAttributeException {
104: throw new IllegalAttributeException(
105: "feature id is immutable");
106: }
107: }
108:
109: static class DefaultGeometrySimpleFeaturePropertyAccessor implements
110: PropertyAccessor {
111:
112: public boolean canHandle(Object object, String xpath,
113: Class target) {
114: if (!"".equals(xpath))
115: return false;
116:
117: // if ( target != Geometry.class )
118: // return false;
119:
120: if (!(object instanceof Feature || object instanceof FeatureType)) {
121: return false;
122: }
123:
124: return true;
125:
126: }
127:
128: public Object get(Object object, String xpath, Class target) {
129: if (object instanceof Feature) {
130: return ((Feature) object).getDefaultGeometry();
131: }
132: if (object instanceof FeatureType) {
133: return ((FeatureType) object).getDefaultGeometry();
134: }
135:
136: return null;
137: }
138:
139: public void set(Object object, String xpath, Object value,
140: Class target) throws IllegalAttributeException {
141:
142: if (object instanceof Feature) {
143: ((Feature) object).setDefaultGeometry((Geometry) value);
144: }
145: if (object instanceof FeatureType) {
146: throw new IllegalAttributeException(
147: "feature type is immutable");
148: }
149:
150: }
151: }
152:
153: static class SimpleFeaturePropertyAccessor implements
154: PropertyAccessor {
155: public boolean canHandle(Object object, String xpath,
156: Class target) {
157: xpath = stripPrefix(xpath);
158:
159: if (object instanceof Feature) {
160: return ((Feature) object).getAttribute(xpath) != null;
161: }
162:
163: if (object instanceof FeatureType) {
164: return ((FeatureType) object).getAttributeType(xpath) != null;
165: }
166:
167: return false;
168: }
169:
170: public Object get(Object object, String xpath, Class target) {
171: xpath = stripPrefix(xpath);
172:
173: if (object instanceof Feature) {
174: return ((Feature) object).getAttribute(xpath);
175: }
176:
177: if (object instanceof FeatureType) {
178: return ((FeatureType) object).getAttributeType(xpath);
179: }
180:
181: return null;
182: }
183:
184: public void set(Object object, String xpath, Object value,
185: Class target) throws IllegalAttributeException {
186: xpath = stripPrefix(xpath);
187:
188: if (object instanceof Feature) {
189: ((Feature) object).setAttribute(xpath, value);
190: }
191:
192: if (object instanceof FeatureType) {
193: throw new IllegalAttributeException(
194: "feature type is immutable");
195: }
196:
197: }
198: }
199:
200: }
|