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.data.test;
006:
007: import org.geoserver.data.CatalogWriter;
008: import org.geotools.data.property.PropertyDataStoreFactory;
009: import java.io.BufferedInputStream;
010: import java.io.BufferedOutputStream;
011: import java.io.BufferedWriter;
012: import java.io.ByteArrayInputStream;
013: import java.io.File;
014: import java.io.FileOutputStream;
015: import java.io.FileWriter;
016: import java.io.IOException;
017: import java.io.InputStream;
018: import java.io.OutputStream;
019: import java.util.Arrays;
020: import java.util.HashMap;
021: import java.util.List;
022:
023: import javax.xml.namespace.QName;
024:
025: /**
026: * Class used to build a mock GeoServer data directory.
027: * <p>
028: * Data is based off the wms and wfs "cite" datasets.
029: * </p>
030: *
031: * @author Justin Deoliveira, The Open Planning Project
032: *
033: */
034: public class MockData {
035: // //// WMS 1.1.1
036: /**
037: * WMS 1.1.1 cite namespace + uri
038: */
039: public static String CITE_PREFIX = "cite";
040: public static String CITE_URI = "http://www.opengis.net/cite";
041:
042: /** featuretype name for WMS 1.1.1 CITE BasicPolygons features */
043: public static QName BASIC_POLYGONS = new QName(CITE_URI,
044: "BasicPolygons", CITE_PREFIX);
045:
046: /** featuretype name for WMS 1.1.1 CITE Bridges features */
047: public static QName BRIDGES = new QName(CITE_URI, "Bridges",
048: CITE_PREFIX);
049:
050: /** featuretype name for WMS 1.1.1 CITE Buildings features */
051: public static QName BUILDINGS = new QName(CITE_URI, "Buildings",
052: CITE_PREFIX);
053:
054: /** featuretype name for WMS 1.1.1 CITE Divided Routes features */
055: public static QName DIVIDED_ROUTES = new QName(CITE_URI,
056: "DividedRoutes", CITE_PREFIX);
057:
058: /** featuretype name for WMS 1.1.1 CITE Forests features */
059: public static QName FORESTS = new QName(CITE_URI, "Forests",
060: CITE_PREFIX);
061:
062: /** featuretype name for WMS 1.1.1 CITE Lakes features */
063: public static QName LAKES = new QName(CITE_URI, "Lakes",
064: CITE_PREFIX);
065:
066: /** featuretype name for WMS 1.1.1 CITE Map Neatliine features */
067: public static QName MAP_NEATLINE = new QName(CITE_URI,
068: "MapNeatline", CITE_PREFIX);
069:
070: /** featuretype name for WMS 1.1.1 CITE Named Places features */
071: public static QName NAMED_PLACES = new QName(CITE_URI,
072: "NamedPlaces", CITE_PREFIX);
073:
074: /** featuretype name for WMS 1.1.1 CITE Ponds features */
075: public static QName PONDS = new QName(CITE_URI, "Ponds",
076: CITE_PREFIX);
077:
078: /** featuretype name for WMS 1.1.1 CITE Road Segments features */
079: public static QName ROAD_SEGMENTS = new QName(CITE_URI,
080: "RoadSegments", CITE_PREFIX);
081:
082: /** featuretype name for WMS 1.1.1 CITE Streams features */
083: public static QName STREAMS = new QName(CITE_URI, "Streams",
084: CITE_PREFIX);
085:
086: // /// WFS 1.0
087: /**
088: * WFS 1.0 cdf namespace + uri
089: */
090: public static String CDF_PREFIX = "cdf";
091: public static String CDF_URI = "http://www.opengis.net/cite/data";
092:
093: /** featuretype name for WFS 1.0 CITE Deletes features */
094: public static QName DELETES = new QName(CDF_URI, "Deletes",
095: CDF_PREFIX);
096:
097: /** featuretype name for WFS 1.0 CITE Fifteen features */
098: public static QName FIFTEEN = new QName(CDF_URI, "Fifteen",
099: CDF_PREFIX);
100:
101: /** featuretype name for WFS 1.0 CITE Inserts features */
102: public static QName INSERTS = new QName(CDF_URI, "Inserts",
103: CDF_PREFIX);
104:
105: /** featuretype name for WFS 1.0 CITE Inserts features */
106: public static QName LOCKS = new QName(CDF_URI, "Locks", CDF_PREFIX);
107:
108: /** featuretype name for WFS 1.0 CITE Nulls features */
109: public static QName NULLS = new QName(CDF_URI, "Nulls", CDF_PREFIX);
110:
111: /** featuretype name for WFS 1.0 CITE Other features */
112: public static QName OTHER = new QName(CDF_URI, "Other", CDF_PREFIX);
113:
114: /** featuretype name for WFS 1.0 CITE Nulls features */
115: public static QName SEVEN = new QName(CDF_URI, "Seven", CDF_PREFIX);
116:
117: /** featuretype name for WFS 1.0 CITE Updates features */
118: public static QName UPDATES = new QName(CDF_URI, "Updates",
119: CDF_PREFIX);
120:
121: /**
122: * cgf namespace + uri
123: */
124: public static String CGF_PREFIX = "cgf";
125: public static String CGF_URI = "http://www.opengis.net/cite/geometry";
126:
127: /** featuretype name for WFS 1.0 CITE Lines features */
128: public static QName LINES = new QName(CGF_URI, "Lines", CGF_PREFIX);
129:
130: /** featuretype name for WFS 1.0 CITE MLines features */
131: public static QName MLINES = new QName(CGF_URI, "MLines",
132: CGF_PREFIX);
133:
134: /** featuretype name for WFS 1.0 CITE MPoints features */
135: public static QName MPOINTS = new QName(CGF_URI, "MPoints",
136: CGF_PREFIX);
137:
138: /** featuretype name for WFS 1.0 CITE MPolygons features */
139: public static QName MPOLYGONS = new QName(CGF_URI, "MPolygons",
140: CGF_PREFIX);
141:
142: /** featuretype name for WFS 1.0 CITE Points features */
143: public static QName POINTS = new QName(CGF_URI, "Points",
144: CGF_PREFIX);
145:
146: /** featuretype name for WFS 1.0 CITE Polygons features */
147: public static QName POLYGONS = new QName(CGF_URI, "Polygons",
148: CGF_PREFIX);
149:
150: // //// WFS 1.1
151: /**
152: * sf namespace + uri
153: */
154: public static String SF_PREFIX = "sf";
155: public static String SF_URI = "http://cite.opengeospatial.org/gmlsf";
156: public static QName PRIMITIVEGEOFEATURE = new QName(SF_URI,
157: "PrimitiveGeoFeature", SF_PREFIX);
158: public static QName AGGREGATEGEOFEATURE = new QName(SF_URI,
159: "AggregateGeoFeature", SF_PREFIX);
160: public static QName GENERICENTITY = new QName(SF_URI,
161: "GenericEntity", SF_PREFIX);
162:
163: // DEFAULT
164: public static String DEFAULT_PREFIX = "gs";
165: public static String DEFAULT_URI = "http://geoserver.org";
166:
167: // public static QName ENTIT\u00C9G\u00C9N\u00C9RIQUE = new QName( SF_URI,
168: // "Entit\u00E9G\u00E9n\u00E9rique", SF_PREFIX );
169:
170: // Extra types
171: public static QName GEOMETRYLESS = new QName(CITE_URI,
172: "Geometryless", CITE_PREFIX);
173:
174: /**
175: * List of all cite types names
176: */
177: public static QName[] TYPENAMES = new QName[] {
178: // WMS 1.1.1
179: BASIC_POLYGONS, BRIDGES, BUILDINGS, DIVIDED_ROUTES,
180: FORESTS, LAKES, MAP_NEATLINE,
181: NAMED_PLACES,
182: PONDS,
183: ROAD_SEGMENTS,
184: STREAMS, // WFS 1.0
185: DELETES, FIFTEEN, INSERTS, LOCKS, NULLS, OTHER, SEVEN,
186: UPDATES, LINES, MLINES, MPOINTS, MPOLYGONS,
187: POINTS,
188: POLYGONS, // WFS 1.1
189: PRIMITIVEGEOFEATURE, AGGREGATEGEOFEATURE, GENERICENTITY,
190: GEOMETRYLESS /* ENTIT\u00C9G\u00C9N\u00C9RIQUE */
191: };
192:
193: /**
194: * List of wms type names.
195: */
196: public static QName[] WMS_TYPENAMES = new QName[] { BASIC_POLYGONS,
197: BRIDGES, BUILDINGS, DIVIDED_ROUTES, FORESTS, LAKES,
198: MAP_NEATLINE, NAMED_PLACES, PONDS, ROAD_SEGMENTS, STREAMS };
199:
200: /**
201: * List of wfs 1.0 type names.
202: */
203: public static QName[] WFS10_TYPENAMES = new QName[] { DELETES,
204: FIFTEEN, INSERTS, LOCKS, NULLS, OTHER, SEVEN, UPDATES,
205: LINES, MLINES, MPOINTS, MPOLYGONS, POINTS, POLYGONS };
206:
207: /**
208: * List of wfs 1.1 type names.
209: */
210: public static QName[] WFS11_TYPENAMES = new QName[] {
211: PRIMITIVEGEOFEATURE, AGGREGATEGEOFEATURE, GENERICENTITY /* ENTIT\u00C9G\u00C9N\u00C9RIQUE */
212: };
213:
214: /** the base of the data directory */
215: File data;
216:
217: /** the 'featureTypes' directory, under 'data' */
218: File featureTypes;
219:
220: /** the 'styles' directory, under 'data' */
221: File styles;
222:
223: /** the 'plugIns' directory under 'data */
224: File plugIns;
225:
226: /** the 'validation' directory under 'data */
227: File validation;
228:
229: /** the 'templates' director under 'data' */
230: File templates;
231:
232: /**
233: * @param base
234: * Base of the GeoServer data directory.
235: *
236: * @throws IOException
237: */
238: public MockData() throws IOException {
239: data = File
240: .createTempFile("mock", "data", new File("./target"));
241: }
242:
243: /**
244: * @return The root of the data directory.
245: */
246: public File getDataDirectoryRoot() {
247: return data;
248: }
249:
250: /**
251: * @return the "featureTypes" directory under the root
252: */
253: public File getFeatureTypesDirectory() {
254: return featureTypes;
255: }
256:
257: /**
258: * Copies some content to a file under the base of the data directory.
259: * <p>
260: * The <code>location</code> is considred to be a path relative to the
261: * data directory root.
262: * </p>
263: * <p>
264: * Note that the resulting file will be deleted when {@link #tearDown()}
265: * is called.
266: * </p>
267: * @param input The content to copy.
268: * @param location A relative path
269: */
270: public void copyTo(InputStream input, String location)
271: throws IOException {
272: copy(input, new File(getDataDirectoryRoot(), location));
273: }
274:
275: /**
276: * Copies some content to a file udner a specific feature type directory
277: * of the data directory.
278: * Example:
279: * <p>
280: * <code>
281: * dd.copyToFeautreTypeDirectory(input,MockData.PrimitiveGeoFeature,"info.xml");
282: * </code>
283: * </p>
284: * @param input The content to copy.
285: * @param featureTypeName The name of the feature type.
286: * @param location The resulting location to copy to relative to the
287: * feautre type directory.
288: */
289: public void copyToFeatureTypeDirectory(InputStream input,
290: QName featureTypeName, String location) throws IOException {
291:
292: copyTo(input, "featureTypes" + File.separator
293: + featureTypeName.getPrefix() + "_"
294: + featureTypeName.getLocalPart() + File.separator
295: + location);
296: }
297:
298: /**
299: * Adds a new feature type.
300: * <p>
301: * Note that callers of this code should call <code>applicationContext.refresh()</code>
302: * in order to force the catalog to reload.
303: * </p>
304: * <p>
305: * The feature type is "empty", in that it has no attributes and no data.
306: * Use {@link #addFeatureType(QName, InputStream)} to add a feature type
307: * with data.
308: * </p>
309: *
310: */
311: public void addFeatureType(QName name) throws IOException {
312:
313: addFeatureType(name, new ByteArrayInputStream("-=".getBytes()));
314: }
315:
316: /**
317: * Adds a new feature type.
318: * <p>
319: * Note that callers of this code should call <code>applicationContext.refresh()</code>
320: * in order to force the catalog to reload.
321: * </p>
322: * <p>
323: * The <tt>properties</tt> parameter is an input stream containing the feature
324: * type info and data to be used by property datastore.
325: * </p>
326: *
327: */
328: public void addFeatureType(QName name, InputStream properties)
329: throws IOException {
330: File directory = new File(data, name.getPrefix());
331: if (!directory.exists()) {
332: directory.mkdir();
333: }
334:
335: //create the properties file
336: File f = new File(directory, name.getLocalPart()
337: + ".properties");
338:
339: //copy over the contents
340: copy(properties, f);
341: info(name);
342:
343: }
344:
345: public void setUp() throws IOException {
346: setUp(TYPENAMES);
347: }
348:
349: /**
350: * Sets up the data directory, creating all the necessary files.
351: *
352: * @throws IOException
353: */
354: public void setUp(QName[] typeNames) throws IOException {
355: data.delete();
356: data.mkdir();
357:
358: // create a featureTypes directory
359: featureTypes = new File(data, "featureTypes");
360: featureTypes.mkdir();
361:
362: // create the styles directory
363: styles = new File(data, "styles");
364: styles.mkdir();
365: //copy over the minimal style and population
366: copy(MockData.class.getResourceAsStream("Default.sld"),
367: new File(styles, "Default.sld"));
368: copy(MockData.class.getResourceAsStream("Population.sld"),
369: new File(styles, "Population.sld"));
370:
371: //plugins
372: plugIns = new File(data, "plugIns");
373: plugIns.mkdir();
374:
375: //validation
376: validation = new File(data, "validation");
377: validation.mkdir();
378:
379: //templates
380: templates = new File(data, "templates");
381: templates.mkdir();
382:
383: //set up the types
384: for (int i = 0; i < typeNames.length; i++) {
385: setup(typeNames[i]);
386: }
387:
388: // create the catalog.xml
389: CatalogWriter writer = new CatalogWriter();
390:
391: // set up the datastores
392: HashMap dataStores = new HashMap();
393:
394: HashMap params = new HashMap();
395: params.put(PropertyDataStoreFactory.DIRECTORY.key, new File(
396: data, CITE_PREFIX));
397: params.put(PropertyDataStoreFactory.NAMESPACE.key, CITE_URI);
398: dataStores.put(CITE_PREFIX, params);
399:
400: params = new HashMap();
401: params.put(PropertyDataStoreFactory.DIRECTORY.key, new File(
402: data, CDF_PREFIX));
403: params.put(PropertyDataStoreFactory.NAMESPACE.key, CDF_URI);
404: dataStores.put(CDF_PREFIX, params);
405:
406: params = new HashMap();
407: params.put(PropertyDataStoreFactory.DIRECTORY.key, new File(
408: data, CGF_PREFIX));
409: params.put(PropertyDataStoreFactory.NAMESPACE.key, CGF_URI);
410: dataStores.put(CGF_PREFIX, params);
411:
412: params = new HashMap();
413: params.put(PropertyDataStoreFactory.DIRECTORY.key, new File(
414: data, SF_PREFIX));
415: params.put(PropertyDataStoreFactory.NAMESPACE.key, SF_URI);
416: dataStores.put(SF_PREFIX, params);
417:
418: HashMap dataStoreNamepaces = new HashMap();
419: dataStoreNamepaces.put(CITE_PREFIX, CITE_PREFIX);
420: dataStoreNamepaces.put(CDF_PREFIX, CDF_PREFIX);
421: dataStoreNamepaces.put(CGF_PREFIX, CGF_PREFIX);
422: dataStoreNamepaces.put(SF_PREFIX, SF_PREFIX);
423:
424: writer.dataStores(dataStores, dataStoreNamepaces);
425:
426: // setup the namespaces
427: HashMap namespaces = new HashMap();
428: namespaces.put(CITE_PREFIX, CITE_URI);
429: namespaces.put(CDF_PREFIX, CDF_URI);
430: namespaces.put(CGF_PREFIX, CGF_URI);
431: namespaces.put(SF_PREFIX, SF_URI);
432: namespaces.put(DEFAULT_PREFIX, DEFAULT_URI);
433: namespaces.put("", DEFAULT_URI);
434:
435: writer.namespaces(namespaces);
436:
437: // styles
438: HashMap styles = new HashMap();
439:
440: List typeList = Arrays.asList(typeNames);
441: for (int i = 0; i < WMS_TYPENAMES.length; i++) {
442: if (typeList.contains(WMS_TYPENAMES[i])) {
443: QName type = WMS_TYPENAMES[i];
444: styles.put(type.getLocalPart(), type.getLocalPart()
445: + ".sld");
446: }
447: }
448: styles.put("Population", "Population.sld");
449: styles.put("Default", "Default.sld");
450:
451: writer.styles(styles);
452:
453: writer.write(new File(data, "catalog.xml"));
454: }
455:
456: void setup(QName type) throws IOException {
457: properties(type);
458: info(type);
459: style(type);
460: }
461:
462: void properties(QName name) throws IOException {
463: // copy over the properties file
464: InputStream from = MockData.class.getResourceAsStream(name
465: .getLocalPart()
466: + ".properties");
467:
468: File directory = new File(data, name.getPrefix());
469: directory.mkdir();
470:
471: File to = new File(directory, name.getLocalPart()
472: + ".properties");
473: copy(from, to);
474: }
475:
476: void copy(InputStream from, File to) throws IOException {
477: OutputStream out = new FileOutputStream(to);
478:
479: byte[] buffer = new byte[4096];
480: int bytes = 0;
481: while ((bytes = from.read(buffer)) != -1)
482: out.write(buffer, 0, bytes);
483:
484: from.close();
485: out.flush();
486: out.close();
487: }
488:
489: void info(QName name) throws IOException {
490: String type = name.getLocalPart();
491: String prefix = name.getPrefix();
492:
493: File featureTypeDir = new File(featureTypes, prefix + "_"
494: + type);
495: featureTypeDir.mkdir();
496:
497: File info = new File(featureTypeDir, "info.xml");
498: info.createNewFile();
499:
500: FileWriter writer = new FileWriter(info);
501: writer.write("<featureType datastore=\"" + prefix + "\">");
502: writer.write("<name>" + type + "</name>");
503: writer.write("<SRS>4326</SRS>");
504: // this mock type may have wrong SRS compared to the actual one in the property files...
505: // let's configure SRS handling not to alter the original one, and have 4326 used only
506: // for capabilities
507: writer.write("<SRSHandling>2</SRSHandling>");
508: writer.write("<title>" + type + "</title>");
509: writer
510: .write("<abstract>abstract about " + type
511: + "</abstract>");
512: writer.write("<numDecimals value=\"8\"/>");
513: writer.write("<keywords>" + type + "</keywords>");
514: writer
515: .write("<latLonBoundingBox dynamic=\"false\" minx=\"-180\" miny=\"-90\" maxx=\"180\" maxy=\"90\"/>");
516:
517: if (MockData.class.getResource(type + ".sld") != null) {
518: writer.write("<styles default=\"" + type + "\"/>");
519: } else {
520: writer.write("<styles default=\"Default\"/>");
521: }
522:
523: writer.write("</featureType>");
524:
525: writer.flush();
526: writer.close();
527: }
528:
529: void style(QName name) throws IOException {
530: String type = name.getLocalPart();
531:
532: //if there is not astyle named "type".sld, use minimal
533: InputStream from = null;
534:
535: if (MockData.class.getResource(type + ".sld") != null) {
536: from = MockData.class.getResourceAsStream(type + ".sld");
537: } else {
538: from = MockData.class.getResourceAsStream("Default.sld");
539: }
540:
541: File to = new File(styles, type + ".sld");
542: copy(from, to);
543: }
544:
545: /**
546: * Kills the data directory, deleting all the files.
547: *
548: * @throws IOException
549: */
550: public void tearDown() throws IOException {
551: delete(templates);
552: delete(validation);
553: delete(plugIns);
554: delete(styles);
555: delete(featureTypes);
556: delete(data);
557:
558: styles = null;
559: featureTypes = null;
560: data = null;
561: }
562:
563: void delete(File dir) throws IOException {
564: File[] files = dir.listFiles();
565:
566: for (int i = 0; i < files.length; i++) {
567: if (files[i].isDirectory()) {
568: delete(files[i]);
569: } else {
570: files[i].delete();
571: }
572: }
573:
574: dir.delete();
575: }
576: }
|