001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.data.complex;
018:
019: import java.util.ArrayList;
020: import java.util.LinkedList;
021: import java.util.List;
022:
023: import org.geotools.data.complex.filter.XPath;
024: import org.geotools.data.feature.FeatureSource2;
025: import org.geotools.data.feature.memory.MemoryDataAccess;
026: import org.geotools.factory.CommonFactoryFinder;
027: import org.geotools.feature.iso.TypeBuilder;
028: import org.geotools.feature.iso.Types;
029: import org.geotools.feature.iso.simple.SimpleFeatureBuilder;
030: import org.geotools.feature.iso.simple.SimpleFeatureFactoryImpl;
031: import org.geotools.feature.iso.simple.SimpleTypeBuilder;
032: import org.geotools.feature.iso.simple.SimpleTypeFactoryImpl;
033: import org.geotools.feature.iso.type.TypeFactoryImpl;
034: import org.opengis.feature.simple.SimpleFeature;
035: import org.opengis.feature.simple.SimpleFeatureFactory;
036: import org.opengis.feature.simple.SimpleFeatureType;
037: import org.opengis.feature.simple.SimpleTypeFactory;
038: import org.opengis.feature.type.AttributeDescriptor;
039: import org.opengis.feature.type.AttributeType;
040: import org.opengis.feature.type.ComplexType;
041: import org.opengis.feature.type.FeatureType;
042: import org.opengis.feature.type.TypeFactory;
043: import org.opengis.feature.type.Name;
044: import org.opengis.filter.FilterFactory;
045: import org.opengis.filter.expression.Expression;
046: import org.xml.sax.helpers.NamespaceSupport;
047:
048: import com.vividsolutions.jts.geom.Coordinate;
049: import com.vividsolutions.jts.geom.GeometryFactory;
050: import com.vividsolutions.jts.geom.Point;
051:
052: /**
053: *
054: * @author Gabriel Roldan, Axios Engineering
055: * @version $Id: TestData.java 28659 2008-01-09 15:11:32Z groldan $
056: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/community-schemas/community-schema-ds/src/test/java/org/geotools/data/complex/TestData.java $
057: * @since 2.4
058: */
059: public class TestData {
060:
061: public final static Name WATERSAMPLE_TYPENAME = Types
062: .typeName("wq_ir_results");
063:
064: private TestData() {
065: }
066:
067: /**
068: * Complex type:
069: * <ul>
070: * wq_plus
071: * <li>sitename
072: * <li>anzlic_no
073: * <li>project_no
074: * <li>measurement (0..*)
075: * <ul>
076: * <li>determinand_description</li>
077: * <li>result</li>
078: * </ul>
079: * </li>
080: * <li>location
081: * </ul>
082: *
083: * @return
084: */
085: public static FeatureType createComplexWaterQualityType() {
086: TypeFactoryImpl tfac = new TypeFactoryImpl();
087: TypeBuilder builder = new TypeBuilder(tfac);
088:
089: FeatureType wq_plusType;
090:
091: AttributeType detdesc = builder.name("determinand_description")
092: .bind(String.class).attribute();
093: AttributeType result = builder.name("result").bind(Float.class)
094: .attribute();
095:
096: builder.setName("measurement");
097: builder.addAttribute("determinand_description", detdesc);
098: builder.addAttribute("result", result);
099:
100: ComplexType MEASUREMENT = builder.complex();
101:
102: /*
103: * <li>sitename <li>anzlic_no <li>project_no <li>location <li>measurement
104: * (0..*) <ul> <li>determinand_description</li> <li>result</li>
105: * </ul>
106: */
107:
108: AttributeType sitename = builder.name("sitename").bind(
109: String.class).attribute();
110: AttributeType anzlic_no = builder.name("anzlic_no").bind(
111: String.class).attribute();
112: AttributeType project_no = builder.name("project_no").bind(
113: String.class).attribute();
114: AttributeType location = builder.name("location").bind(
115: Point.class).geometry();
116:
117: builder.setName("wq_plus");
118: builder.addAttribute("sitename", sitename);
119: builder.addAttribute("anzlic_no", anzlic_no);
120: builder.addAttribute("project_no", project_no);
121:
122: builder.cardinality(0, Integer.MAX_VALUE);
123: builder.addAttribute("measurement", MEASUREMENT);
124:
125: builder.cardinality(1, 1);
126: builder.addAttribute("location", location);
127:
128: wq_plusType = builder.feature();
129:
130: return wq_plusType;
131: }
132:
133: public static FeatureType createComplexWaterSampleType() {
134: TypeFactoryImpl tfac = new TypeFactoryImpl();
135: TypeBuilder builder = new TypeBuilder(tfac);
136:
137: FeatureType sampleType;
138:
139: AttributeType parameter = builder.name("parameter").bind(
140: String.class).attribute();
141: AttributeType value = builder.name("value").bind(Double.class)
142: .attribute();
143:
144: builder.setName("measurement");
145: builder.addAttribute("parameter", parameter);
146: builder.addAttribute("value", value);
147: ComplexType MEASUREMENT = builder.complex();
148:
149: builder.setName("sample");
150: builder.cardinality(0, Integer.MAX_VALUE);
151: builder.addAttribute("measurement", MEASUREMENT);
152:
153: sampleType = builder.feature();
154:
155: return sampleType;
156: }
157:
158: /**
159: *
160: * <pre>
161: * </pre>
162: *
163: * @param targetFeature
164: * @return
165: * @throws Exception
166: */
167: public static List/* <AttributeMapping> */createMappingsColumnsAndValues(
168: AttributeDescriptor targetFeature) throws Exception {
169:
170: List mappings = new LinkedList();
171: AttributeMapping attMapping;
172: Expression source;
173: String target;
174:
175: FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
176:
177: source = ff.literal("ph");
178: target = "sample/measurement[1]/parameter";
179: // empty nssupport as the test properties have no namespace
180: NamespaceSupport namespaces = new NamespaceSupport();
181: attMapping = new AttributeMapping(null, source, XPath.steps(
182: targetFeature, target, namespaces));
183: mappings.add(attMapping);
184:
185: source = ff.property("ph");
186: target = "sample/measurement[1]/value";
187: attMapping = new AttributeMapping(null, source, XPath.steps(
188: targetFeature, target, namespaces));
189: mappings.add(attMapping);
190:
191: source = ff.literal("temp");
192: target = "sample/measurement[2]/parameter";
193: attMapping = new AttributeMapping(null, source, XPath.steps(
194: targetFeature, target, namespaces));
195: mappings.add(attMapping);
196:
197: source = ff.property("temp");
198: target = "sample/measurement[2]/value";
199: attMapping = new AttributeMapping(null, source, XPath.steps(
200: targetFeature, target, namespaces));
201: mappings.add(attMapping);
202:
203: source = ff.literal("turbidity");
204: target = "sample/measurement[3]/parameter";
205: attMapping = new AttributeMapping(null, source, XPath.steps(
206: targetFeature, target, namespaces));
207: mappings.add(attMapping);
208:
209: source = ff.property("turbidity");
210: target = "sample/measurement[3]/value";
211: attMapping = new AttributeMapping(null, source, XPath.steps(
212: targetFeature, target, namespaces));
213: mappings.add(attMapping);
214:
215: return mappings;
216: }
217:
218: /**
219: * <p>
220: * Flat FeatureType:
221: * <ul>
222: * wq_ir_results
223: * <li> station_no</li>
224: * <li> sitename</li>
225: * <li> anzlic_no</li>
226: * <li> project_no</li>
227: * <li> id</li>
228: * <li> sample_collection_date</li>
229: * <li> determinand_description</li>
230: * <li> results_value</li>
231: * <li> location</li>
232: * </ul>
233: * </p>
234: * <p>
235: * Complex type:
236: * <ul>
237: * wq_plus
238: * <li>sitename
239: * <li>anzlic_no
240: * <li>project_no
241: * <li>location
242: * <li>measurement (0..*)
243: * <ul>
244: * <li>determinand_description</li>
245: * <li>result</li>
246: * </ul>
247: * </li>
248: * </ul>
249: * </p>
250: * <p>
251: * Mappings definition:
252: *
253: * <pre>
254: * <strong>wq_ir_results</strong> <strong>wq_plus</strong>
255: * station_no --> wq_plus@id
256: * sitename --> sitename
257: * anzlic_no --> anzlic_no
258: * project_no --> project_no
259: * id --> measurement/@id
260: * sample_collection_date--> [not used]
261: * determinand_description-->measurement/determinand_description
262: * results_value -->measurement/result
263: * location -->location
264: * </pre>
265: *
266: * </p>
267: *
268: * @param simpleStore
269: * @return
270: * @throws Exception
271: */
272: public static FeatureTypeMapping createMappingsGroupByStation(
273: MemoryDataAccess simpleStore) throws Exception {
274: Name sourceTypeName = WATERSAMPLE_TYPENAME;
275: final FeatureSource2 wsSource = (FeatureSource2) simpleStore
276: .access(sourceTypeName);
277:
278: FeatureType targetType = createComplexWaterQualityType();
279: TypeFactory tf = new TypeFactoryImpl();
280: AttributeDescriptor targetFeature = tf
281: .createAttributeDescriptor(targetType, targetType
282: .getName(), 0, Integer.MAX_VALUE, true, null);
283:
284: List mappings = new LinkedList();
285: Expression id;
286: Expression source;
287: String target;
288:
289: FilterFactory ff = CommonFactoryFinder.getFilterFactory(null);
290:
291: id = ff.property("station_no");
292: source = Expression.NIL;
293: target = "wq_plus";
294: NamespaceSupport namespaces = new NamespaceSupport();
295: mappings.add(new AttributeMapping(id, source, XPath.steps(
296: targetFeature, target, namespaces)));
297:
298: source = ff.property("sitename");
299: target = "wq_plus/sitename";
300: mappings.add(new AttributeMapping(null, source, XPath.steps(
301: targetFeature, target, namespaces)));
302:
303: source = ff.property("anzlic_no");
304: target = "wq_plus/anzlic_no";
305: mappings.add(new AttributeMapping(null, source, XPath.steps(
306: targetFeature, target, namespaces)));
307:
308: source = ff.property("project_no");
309: target = "wq_plus/project_no";
310: mappings.add(new AttributeMapping(null, source, XPath.steps(
311: targetFeature, target, namespaces)));
312:
313: id = ff.property("id[1]");
314: source = null;
315: target = "wq_plus/measurement";
316: mappings.add(new AttributeMapping(id, source, XPath.steps(
317: targetFeature, target, namespaces), null, true, null));
318:
319: source = ff.property("determinand_description");
320: target = "wq_plus/measurement/determinand_description";
321: mappings.add(new AttributeMapping(null, source, XPath.steps(
322: targetFeature, target, namespaces)));
323:
324: source = ff.property("results_value");
325: target = "wq_plus/measurement/result";
326: mappings.add(new AttributeMapping(null, source, XPath.steps(
327: targetFeature, target, namespaces)));
328:
329: source = ff.property("location");
330: target = "wq_plus/location";
331: mappings.add(new AttributeMapping(null, source, XPath.steps(
332: targetFeature, target, namespaces)));
333:
334: FeatureTypeMapping mapper = new FeatureTypeMapping(wsSource,
335: targetFeature, mappings, namespaces);
336:
337: List/* <String> */groupingAttributes = new ArrayList/* <String> */();
338: groupingAttributes.add("station_no");
339: groupingAttributes.add("sitename");
340: groupingAttributes.add("anzlic_no");
341: groupingAttributes.add("project_no");
342: groupingAttributes.add("location");
343:
344: mapper.setGroupByAttNames(groupingAttributes);
345:
346: return mapper;
347: }
348:
349: /**
350: * Creates a flat FeatureType <code>wq_ir_results</code> with a structure
351: * like the following, from which a complex one should be constructed
352: * grouping by station_no attribute.
353: * <p>
354: * Following this sample schema, a total of 10 unique station_no identifiers
355: * will be created, and for each one, a total of N desagregate rows with the
356: * same station_no, where N goes from 1 to 10. So for the first station_no
357: * there will be just one occurrence and the last one will have 10.
358: * </p>
359: * <p>
360: * <table>
361: * <tr>
362: * <td> station_no (string) </td>
363: * <td> sitename (string)</td>
364: * <td> anzlic_no (string)</td>
365: * <td> project_no (string)</td>
366: * <td> id (string)</td>
367: * <td> sample_collection_date (string)</td>
368: * <td> determinand_description (string)</td>
369: * <td> results_value (float)</td>
370: * <td> location (Point)</td>
371: * </tr>
372: * <tr>
373: * <td> station_1 </td>
374: * <td> sitename_1 </td>
375: * <td> anzlic_no_1 </td>
376: * <td> project_no_1 </td>
377: * <td> id_1_1 </td>
378: * <td> sample_collection_date_1_1 </td>
379: * <td> determinand_description_1_1 </td>
380: * <td> 1.1 </td>
381: * <td> POINT(1, 1) </td>
382: * </tr>
383: * <tr>
384: * <td> station_2 </td>
385: * <td> sitename_2 </td>
386: * <td> anzlic_no_2 </td>
387: * <td> project_no_2 </td>
388: * <td> id_2_1 </td>
389: * <td> sample_collection_date_2_1 </td>
390: * <td> determinand_description_2_1 </td>
391: * <td> 2.1 </td>
392: * <td> POINT(2, 2) </td>
393: * </tr>
394: * <tr>
395: * <td> station_2 </td>
396: * <td> sitename_2 </td>
397: * <td> anzlic_no_2 </td>
398: * <td> project_no_2 </td>
399: * <td> id_2_2 </td>
400: * <td> sample_collection_date_2_2 </td>
401: * <td> determinand_description_2_2 </td>
402: * <td> 2.2 </td>
403: * <td> POINT(2, 2) </td>
404: * </tr>
405: * <tr>
406: * <td colspan="9">...</td>
407: * </tr>
408: * <tr>
409: * <td> station_10 </td>
410: * <td> sitename_10 </td>
411: * <td> anzlic_no_10 </td>
412: * <td> project_no_10 </td>
413: * <td> id_10_10 </td>
414: * <td> sample_collection_date_10_9 </td>
415: * <td> determinand_description_10_9 </td>
416: * <td> 10.10 </td>
417: * <td> POINT(10, 10) </td>
418: * </tr>
419: * <tr>
420: * <td> station_10 </td>
421: * <td> sitename_10 </td>
422: * <td> anzlic_no_10 </td>
423: * <td> project_no_10 </td>
424: * <td> id_10_10 </td>
425: * <td> sample_collection_date_10_10 </td>
426: * <td> determinand_description_10_10 </td>
427: * <td> 10.10 </td>
428: * <td> POINT(10, 10) </td>
429: * </tr>
430: * </table>
431: * </p>
432: *
433: * @return
434: * @throws Exception
435: */
436: public static MemoryDataAccess createDenormalizedWaterQualityResults()
437: throws Exception {
438: MemoryDataAccess dataStore = new MemoryDataAccess();
439: SimpleTypeFactory tf = new SimpleTypeFactoryImpl();
440: SimpleTypeBuilder builder = new SimpleTypeBuilder(tf);
441:
442: builder.setName(TestData.WATERSAMPLE_TYPENAME.getLocalPart());
443:
444: builder.addAttribute("station_no", String.class);
445: builder.addAttribute("sitename", String.class);
446: builder.addAttribute("anzlic_no", String.class);
447: builder.addAttribute("project_no", String.class);
448: builder.addAttribute("id", String.class);
449: builder.addAttribute("sample_collection_date", String.class);
450: builder.addAttribute("determinand_description", String.class);
451: builder.addAttribute("results_value", Float.class);
452: builder.addGeometry("location", Point.class);
453:
454: SimpleFeatureType type = builder.feature();
455:
456: dataStore.createSchemaInternal(type);
457:
458: final int NUM_STATIONS = 10;
459: SimpleFeatureFactory af = new SimpleFeatureFactoryImpl();
460: GeometryFactory gf = new GeometryFactory();
461:
462: SimpleFeatureBuilder fb = new SimpleFeatureBuilder(
463: new SimpleFeatureFactoryImpl());
464:
465: for (int groupValue = 1; groupValue <= NUM_STATIONS; groupValue++) {
466:
467: for (int measurement = 1; measurement <= groupValue; measurement++) {
468: fb.init();
469: fb.setType(type);
470: String fid = type.getName().getLocalPart() + "."
471: + groupValue + "." + measurement;
472:
473: fb.add("station_no." + groupValue);
474: fb.add("sitename" + groupValue);
475: fb.add("anzlic_no" + groupValue);
476: fb.add("project_no" + groupValue);
477:
478: String sufix = "_" + groupValue + "_" + measurement;
479: fb.add("id" + sufix);
480: fb.add("sample_collection_date" + sufix);
481: fb.add("determinand_description" + sufix);
482: fb.add(new Float(groupValue + "." + measurement));
483:
484: fb.add(gf.createPoint(new Coordinate(groupValue,
485: groupValue)));
486:
487: SimpleFeature f = fb.feature(fid);
488: dataStore.addFeatureInternal(f);
489: }
490: }
491: return dataStore;
492: }
493:
494: }
|