001: /* Copyright (c) 2001 - 2007 TOPP - www.openplans.org. All rights reserved.
002: * This code is licensed under the GPL 2.0 license, availible at the root
003: * application directory.
004: */
005: package org.geoserver.wfs.kvp;
006:
007: import com.vividsolutions.jts.geom.Envelope;
008: import net.opengis.wfs.QueryType;
009: import org.eclipse.emf.ecore.EObject;
010: import org.geoserver.wfs.WFSException;
011: import org.geotools.feature.FeatureType;
012: import org.geotools.geometry.jts.ReferencedEnvelope;
013: import org.geotools.gml2.bindings.GML2EncodingUtils;
014: import org.geotools.xml.EMFUtils;
015: import org.opengis.filter.Filter;
016: import org.opengis.filter.FilterFactory;
017: import org.opengis.filter.identity.FeatureId;
018: import org.opengis.filter.spatial.BBOX;
019: import org.opengis.referencing.crs.CoordinateReferenceSystem;
020: import org.vfny.geoserver.global.Data;
021: import org.vfny.geoserver.global.FeatureTypeInfo;
022: import java.util.ArrayList;
023: import java.util.Collections;
024: import java.util.HashSet;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028: import java.util.Set;
029:
030: import javax.xml.namespace.QName;
031:
032: public class GetFeatureKvpRequestReader extends WFSKvpRequestReader {
033: /**
034: * Catalog used in qname parsing
035: */
036: Data catalog;
037:
038: /**
039: * Factory used in filter parsing
040: */
041: FilterFactory filterFactory;
042:
043: public GetFeatureKvpRequestReader(Class requestBean, Data catalog,
044: FilterFactory filterFactory) {
045: super (requestBean);
046: this .catalog = catalog;
047: this .filterFactory = filterFactory;
048: }
049:
050: /**
051: * Performs additinon GetFeature kvp parsing requirements
052: */
053: public Object read(Object request, Map kvp, Map rawKvp)
054: throws Exception {
055: request = super .read(request, kvp, rawKvp);
056:
057: // make sure the filter is specified in just one way
058: ensureMutuallyExclusive(kvp, new String[] { "featureId",
059: "filter", "bbox", "cql_filter" });
060:
061: //get feature has some additional parsing requirements
062: EObject eObject = (EObject) request;
063:
064: //outputFormat
065: if (!EMFUtils.isSet(eObject, "outputFormat")) {
066: //set the default
067: String version = (String) EMFUtils.get(eObject, "version");
068:
069: if ((version != null) && version.startsWith("1.0")) {
070: EMFUtils.set(eObject, "outputFormat", "GML2");
071: } else {
072: EMFUtils.set(eObject, "outputFormat",
073: "text/xml; subtype=gml/3.1.1");
074: }
075: }
076:
077: //typeName
078: if (kvp.containsKey("typeName")) {
079: //HACK, the kvp reader gives us a list of QName, need to wrap in
080: // another
081: List typeName = (List) kvp.get("typeName");
082: List list = new ArrayList();
083:
084: for (Iterator itr = typeName.iterator(); itr.hasNext();) {
085: QName qName = (QName) itr.next();
086: List l = new ArrayList();
087: l.add(qName);
088: list.add(l);
089: }
090:
091: kvp.put("typeName", list);
092: querySet(eObject, "typeName", list);
093: } else {
094: //check for featureId and infer typeName
095: if (kvp.containsKey("featureId")) {
096: //use featureId to infer type Names
097: List featureId = (List) kvp.get("featureId");
098:
099: ArrayList typeNames = new ArrayList();
100:
101: QNameKvpParser parser = new QNameKvpParser("typeName",
102: catalog);
103:
104: for (int i = 0; i < featureId.size(); i++) {
105: String fid = (String) featureId.get(i);
106: int pos = fid.indexOf(".");
107:
108: if (pos != -1) {
109: String typeName = fid.substring(0, fid
110: .lastIndexOf("."));
111:
112: //add to a list to set on the query
113: List parsed = (List) parser.parse(typeName);
114: typeNames.add(parsed);
115: }
116: }
117:
118: querySet(eObject, "typeName", typeNames);
119: }
120: }
121:
122: //filter
123: if (kvp.containsKey("filter")) {
124: querySet(eObject, "filter", (List) kvp.get("filter"));
125: } else if (kvp.containsKey("cql_filter")) {
126: querySet(eObject, "filter", (List) kvp.get("cql_filter"));
127: } else if (kvp.containsKey("featureId")) {
128: //set filter from featureId
129: List featureIdList = (List) kvp.get("featureId");
130: Set ids = new HashSet();
131:
132: for (Iterator i = featureIdList.iterator(); i.hasNext();) {
133: String fid = (String) i.next();
134: FeatureId featureId = filterFactory.featureId(fid);
135: ids.add(featureId);
136: }
137: // build a single feature id filter
138: List filters = Collections.singletonList(filterFactory
139: .id(ids));
140:
141: querySet(eObject, "filter", filters);
142: } else if (kvp.containsKey("bbox")) {
143: //set filter from bbox
144: Envelope bbox = (Envelope) kvp.get("bbox");
145:
146: List queries = (List) EMFUtils.get(eObject, "query");
147: List filters = new ArrayList();
148:
149: for (Iterator q = queries.iterator(); q.hasNext();) {
150: QueryType query = (QueryType) q.next();
151: List typeName = query.getTypeName();
152: Filter filter = null;
153:
154: if (typeName.size() > 1) {
155: //TODO: not sure what to do here, just going to and them up
156: List and = new ArrayList(typeName.size());
157:
158: for (Iterator t = typeName.iterator(); t.hasNext();) {
159: and.add(bboxFilter((QName) t.next(), bbox));
160: }
161:
162: filter = filterFactory.and(and);
163: } else {
164: filter = bboxFilter((QName) typeName.get(0), bbox);
165: }
166:
167: filters.add(filter);
168: }
169:
170: querySet(eObject, "filter", filters);
171: }
172:
173: //propertyName
174: if (kvp.containsKey("propertyName")) {
175: querySet(eObject, "propertyName", (List) kvp
176: .get("propertyName"));
177: }
178:
179: //sortBy
180: if (kvp.containsKey("sortBy")) {
181: querySet(eObject, "sortBy", (List) kvp.get("sortBy"));
182: }
183:
184: //srsName
185: if (kvp.containsKey("srsName")) {
186: querySet(eObject, "srsName", (List) kvp.get("srsName"));
187: }
188:
189: //featureversion
190: if (kvp.containsKey("featureVersion")) {
191: querySet(eObject, "featureVersion", Collections
192: .singletonList((String) kvp.get("featureVersion")));
193: }
194:
195: return request;
196: }
197:
198: /**
199: * Given a set of keys, this method will ensure that no two keys are specified at the same time
200: * @param kvp
201: * @param keys
202: */
203: private void ensureMutuallyExclusive(Map kvp, String[] keys) {
204: for (int i = 0; i < keys.length; i++) {
205: if (kvp.containsKey(keys[i])) {
206: for (int j = i + 1; j < keys.length; j++) {
207: if (kvp.containsKey(keys[j])) {
208: String msg = keys[i]
209: + " and "
210: + keys[j]
211: + " both specified but are mutually exclusive";
212: throw new WFSException(msg);
213: }
214: }
215: }
216: }
217: }
218:
219: BBOX bboxFilter(QName typeName, Envelope bbox) throws Exception {
220: FeatureTypeInfo featureTypeInfo = catalog
221: .getFeatureTypeInfo(typeName);
222: FeatureType featureType = featureTypeInfo.getFeatureType();
223:
224: //TODO: should this be applied to all geometries?
225: String name = featureType.getDefaultGeometry().getName();
226:
227: //get the epsg code
228: String epsgCode = null;
229: if (bbox instanceof ReferencedEnvelope) {
230: CoordinateReferenceSystem crs = ((ReferencedEnvelope) bbox)
231: .getCoordinateReferenceSystem();
232: if (crs != null) {
233: epsgCode = GML2EncodingUtils.crs(crs);
234: }
235: }
236:
237: return filterFactory.bbox(name, bbox.getMinX(), bbox.getMinY(),
238: bbox.getMaxX(), bbox.getMaxY(), epsgCode);
239: }
240:
241: protected void querySet(EObject request, String property,
242: List values) throws WFSException {
243: //no values specified, do nothing
244: if (values == null) {
245: return;
246: }
247:
248: List query = (List) EMFUtils.get(request, "query");
249:
250: int m = values.size();
251: int n = query.size();
252:
253: if ((m == 1) && (n > 1)) {
254: //apply single value to all queries
255: EMFUtils.set(query, property, values.get(0));
256:
257: return;
258: }
259:
260: //match up sizes
261: if (m > n) {
262: if (n == 0) {
263: //make same size, with empty objects
264: for (int i = 0; i < m; i++) {
265: query.add(getWfsFactory().createQueryType());
266: }
267: } else if (n == 1) {
268: //clone single object up to
269: EObject q = (EObject) query.get(0);
270:
271: for (int i = 1; i < m; i++) {
272: query.add(EMFUtils.clone(q, getWfsFactory()));
273: }
274:
275: return;
276: } else {
277: //illegal
278: String msg = "Specified " + m + " " + property
279: + " for " + n + " queries.";
280: throw new WFSException(msg);
281: }
282: }
283:
284: EMFUtils.set(query, property, values);
285: }
286: }
|