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.vfny.geoserver.config;
006:
007: import com.vividsolutions.jts.geom.Envelope;
008: import com.vividsolutions.jts.geom.Envelope;
009: import com.vividsolutions.jts.geom.GeometryFactory;
010: import com.vividsolutions.jts.geom.GeometryFactory;
011: import org.geotools.feature.AttributeType;
012: import org.geotools.feature.AttributeType;
013: import org.geotools.feature.FeatureType;
014: import org.geotools.feature.FeatureType;
015: import org.geotools.feature.GeometryAttributeType;
016: import org.geotools.referencing.CRS;
017: import org.opengis.filter.Filter;
018: import org.opengis.referencing.crs.CoordinateReferenceSystem;
019: import org.vfny.geoserver.global.FeatureTypeInfo;
020: import org.vfny.geoserver.global.dto.AttributeTypeInfoDTO;
021: import org.vfny.geoserver.global.dto.CloneLibrary;
022: import org.vfny.geoserver.global.dto.FeatureTypeInfoDTO;
023: import org.vfny.geoserver.global.dto.FeatureTypeInfoDTO;
024: import java.util.ArrayList;
025: import java.util.Collections;
026: import java.util.HashSet;
027: import java.util.Iterator;
028: import java.util.LinkedList;
029: import java.util.List;
030: import java.util.Set;
031: import java.util.logging.Logger;
032:
033: /**
034: * User interface FeatureType staging area.
035: *
036: * @author dzwiers, Refractions Research, Inc.
037: * @version $Id: FeatureTypeConfig.java 8391 2008-02-13 16:44:23Z aaime $
038: */
039: public class FeatureTypeConfig {
040: protected static Logger LOGGER = org.geotools.util.logging.Logging
041: .getLogger("org.vfny.geoserver.config");
042:
043: /** The Id of the datastore which should be used to get this featuretype. */
044: private String dataStoreId;
045:
046: /** An EPSG:4326 bounding box for this featuretype */
047: private Envelope latLongBBox;
048:
049: /** A native CRS bounding box for this featuretype */
050: private Envelope nativeBBox;
051:
052: /** native wich EPGS code for the FeatureTypeInfo */
053: private int SRS;
054:
055: /**
056: * Either force declared or reproject from native to declared, see {@link FeatureTypeInfo#FORCE}
057: * and {@link FeatureTypeInfo#REPROJECT}
058: */
059: private int SRSHandling;
060:
061: /**
062: * This is an ordered list of AttributeTypeInfoConfig.
063: * <p>
064: * These attribtue have been defined by the user (or schema.xml file).
065: * Additional attribute may be assumed based on the schemaBase
066: * </p>
067: * <p>
068: * If this is <code>null</code>, all Attribtue information
069: * will be generated. An empty list is used to indicate that only
070: * attribtues indicated by the schemaBase will be returned.
071: * </p>
072: */
073: private List schemaAttributes;
074:
075: /** Name (must match DataStore typeName). */
076: private String name;
077:
078: /**
079: * The user facing alias for this feature type, if any
080: */
081: private String alias;
082:
083: /**
084: *
085: */
086: private String wmsPath;
087:
088: /**
089: * The schema name.
090: * <p>
091: * Usually name + "_Type"
092: * </p>
093: */
094: private String schemaName;
095:
096: /**
097: * The schema base.
098: * <p>
099: * The schema base is used to indicate additional attribtues, not defined
100: * by the user. These attribute are fixed -not be edited by the user.
101: * </p>
102: * <p>
103: * This easiest is "AbstractFeatureType"
104: * </p>
105: */
106: private String schemaBase;
107:
108: /**
109: * The featuretype directory name.
110: * <p>
111: * This is used to write to, and is stored because it may be longer than
112: * the name, as this often includes information about the source of the
113: * featuretype.
114: * </p>
115: * <p>
116: * A common naming convention is: <code>dataStoreId + "_" + name</code>
117: * </p>
118: */
119: private String dirName;
120:
121: /**
122: * The featuretype title.
123: * <p>
124: * Not sure what this is used for - usually name+"_Type"
125: */
126: private String title;
127:
128: /** The feature type abstract, short explanation of this featuretype. */
129: private String _abstract;
130:
131: /**
132: * A list of keywords to associate with this featuretype.
133: * <p>
134: * Keywords are destinct strings, often rendered surrounded by brackets
135: * to aid search engines.
136: * </p>
137: */
138: private Set keywords;
139:
140: /**
141: * A list of metadata links to associate with this featuretype.
142: * <p>
143: * Metadata URLs are distinct URLs.
144: * </p>
145: */
146: private Set metadataLinks;
147:
148: /** Configuration information used to specify numeric percision */
149: private int numDecimals;
150:
151: /**
152: * Filter used to limit query.
153: * <p>
154: * TODO: Check the following comment - I don't belive it.
155: * The list of exposed attributes. If the list is empty or not present at
156: * all, all the FeatureTypeInfo's attributes are exposed, if is present,
157: * only those oattributes in this list will be exposed by the services
158: * </p>
159: */
160: private Filter definitionQuery = null;
161:
162: /**
163: * The default style name.
164: */
165: private String defaultStyle;
166:
167: /**
168: * Other WMS Styles
169: */
170: private ArrayList styles;
171:
172: /**
173: * A featureType-specific override for the defaultMaxAge defined in WMSConfig. This value is added the
174: * headers of generated maps, marking them as being both "cache-able" and designating the time for which
175: * they are to remain valid. The specific header added is "CacheControl: max-age="
176: */
177: private String cacheMaxAge;
178:
179: /**
180: * Should we be adding the CacheControl: max-age header to outgoing maps which include this layer?
181: */
182: private boolean cachingEnabled;
183:
184: /**
185: * The maximum number of features to be served for this feature type (it's understood
186: * it's less than the global maxFeatures). 0 is used as the "no limit" flag
187: */
188: private int maxFeatures = 0;
189:
190: /**
191: * Package visible constructor for test cases
192: */
193: FeatureTypeConfig() {
194: }
195:
196: /**
197: * Creates a FeatureTypeInfo to represent an instance with default data.
198: *
199: * @param dataStoreId ID for data store in catalog
200: * @param schema Geotools2 FeatureType
201: * @param generate True to generate entries for all attribtues
202: */
203: public FeatureTypeConfig(String dataStoreId, FeatureType schema,
204: boolean generate) {
205: if ((dataStoreId == null) || (dataStoreId.length() == 0)) {
206: throw new IllegalArgumentException(
207: "dataStoreId is required for FeatureTypeConfig");
208: }
209:
210: if (schema == null) {
211: throw new IllegalArgumentException(
212: "FeatureType is required for FeatureTypeConfig");
213: }
214:
215: this .dataStoreId = dataStoreId;
216: latLongBBox = new Envelope();
217: nativeBBox = new Envelope();
218: SRS = lookupSRS(schema.getDefaultGeometry());
219:
220: if (generate) {
221: this .schemaAttributes = new ArrayList();
222:
223: for (int i = 0; i < schema.getAttributeCount(); i++) {
224: AttributeType attrib = schema.getAttributeType(i);
225: this .schemaAttributes.add(new AttributeTypeInfoConfig(
226: attrib));
227: }
228: } else {
229: this .schemaAttributes = null;
230: }
231:
232: defaultStyle = "";
233: styles = new ArrayList();
234: name = schema.getTypeName();
235: wmsPath = "/";
236: title = schema.getTypeName() + "_Type";
237: _abstract = "Generated from " + dataStoreId;
238: keywords = new HashSet();
239: keywords.add(dataStoreId);
240: keywords.add(name);
241: metadataLinks = new HashSet();
242: numDecimals = 8;
243: definitionQuery = null;
244: dirName = dataStoreId + "_" + name;
245: schemaName = name + "_Type";
246: schemaBase = "gml:AbstractFeatureType";
247:
248: cachingEnabled = false;
249: cacheMaxAge = null;
250: }
251:
252: /**
253: * TODO: this method is duplicated with CoveragesEditorAction and should be replaced by
254: * an equivalent method in CRS class. Once the methods is added, forward to the CRS class.
255: * @param defaultGeometry
256: * @return
257: */
258: private int lookupSRS(GeometryAttributeType defaultGeometry) {
259: // NPE avoidance
260: if (defaultGeometry == null) {
261: return -1;
262: }
263:
264: // try the (deprecated) geometry factory, we don't want to break data stores that
265: // do correctly set it
266: GeometryFactory geometryFactory = defaultGeometry
267: .getGeometryFactory();
268:
269: if ((geometryFactory != null)
270: && (geometryFactory.getSRID() != 0)) {
271: return geometryFactory.getSRID();
272: }
273:
274: return 0;
275:
276: // // try to reverse engineer the SRID from the coordinate system
277: // CoordinateReferenceSystem ref = defaultGeometry.getCoordinateSystem();
278: // String code = CRS.lookupIdentifier(ref, Collections.singleton("EPSG"), true);
279: // if(code == null)
280: // return 0;
281: // if(code.startsWith("EPSG:")) {
282: // code = code.substring(5);
283: // }
284: // try {
285: // return Integer.parseInt(code);
286: // } catch(NumberFormatException e) {
287: // LOGGER.severe("Could not parse EPSG code: " + code);
288: // return 0;
289: // }
290: }
291:
292: /**
293: * FeatureTypeInfo constructor.
294: *
295: * <p>
296: * Creates a copy of the FeatureTypeInfoDTO provided. All the data
297: * structures are cloned.
298: * </p>
299: *
300: * @param dto The FeatureTypeInfoDTO to copy.
301: *
302: * @throws NullPointerException DOCUMENT ME!
303: */
304: public FeatureTypeConfig(FeatureTypeInfoDTO dto) {
305: if (dto == null) {
306: throw new NullPointerException(
307: "Non null FeatureTypeInfoDTO required");
308: }
309:
310: dataStoreId = dto.getDataStoreId();
311: latLongBBox = new Envelope(dto.getLatLongBBox());
312: nativeBBox = new Envelope(dto.getNativeBBox());
313: SRS = dto.getSRS();
314: SRSHandling = dto.getSRSHandling();
315:
316: if (dto.getSchemaAttributes() == null) {
317: schemaAttributes = null;
318: } else {
319: schemaAttributes = new LinkedList();
320:
321: Iterator i = dto.getSchemaAttributes().iterator();
322:
323: while (i.hasNext()) {
324: schemaAttributes.add(new AttributeTypeInfoConfig(
325: (AttributeTypeInfoDTO) i.next()));
326: }
327: }
328:
329: name = dto.getName();
330: alias = dto.getAlias();
331: wmsPath = dto.getWmsPath();
332: title = dto.getTitle();
333: _abstract = dto.getAbstract();
334: numDecimals = dto.getNumDecimals();
335: definitionQuery = dto.getDefinitionQuery();
336:
337: try {
338: keywords = new HashSet(dto.getKeywords());
339: } catch (Exception e) {
340: keywords = new HashSet();
341: }
342:
343: try {
344: metadataLinks = new HashSet(dto.getMetadataLinks());
345: } catch (Exception e) {
346: metadataLinks = new HashSet();
347: }
348:
349: defaultStyle = dto.getDefaultStyle();
350: styles = dto.getStyles();
351: dirName = dto.getDirName();
352: schemaName = dto.getSchemaName();
353: schemaBase = dto.getSchemaBase();
354:
355: cachingEnabled = dto.isCachingEnabled();
356: cacheMaxAge = dto.getCacheMaxAge();
357: maxFeatures = dto.getMaxFeatures();
358: }
359:
360: /**
361: * Implement toDTO.
362: *
363: * <p>
364: * Creates a represetation of this object as a FeatureTypeInfoDTO
365: * </p>
366: *
367: * @return a representation of this object as a FeatureTypeInfoDTO
368: *
369: * @see org.vfny.geoserver.config.DataStructure#toDTO()
370: */
371: public FeatureTypeInfoDTO toDTO() {
372: FeatureTypeInfoDTO f = new FeatureTypeInfoDTO();
373: f.setDataStoreId(dataStoreId);
374: f.setLatLongBBox(CloneLibrary.clone(latLongBBox));
375: f.setNativeBBox(CloneLibrary.clone(nativeBBox));
376: f.setSRS(SRS);
377: f.setSRSHandling(SRSHandling);
378:
379: if (schemaAttributes == null) {
380: // Use generated default attributes
381: f.setSchemaAttributes(null);
382: } else {
383: // Use user provided attribtue + schemaBase attribtues
384: List s = new ArrayList();
385:
386: for (int i = 0; i < schemaAttributes.size(); i++) {
387: s.add(((AttributeTypeInfoConfig) schemaAttributes
388: .get(i)).toDTO());
389: }
390:
391: f.setSchemaAttributes(s);
392: }
393:
394: f.setName(name);
395: f.setAlias(alias);
396: f.setWmsPath(wmsPath);
397: f.setTitle(title);
398: f.setAbstract(_abstract);
399: f.setNumDecimals(numDecimals);
400: f.setDefinitionQuery(definitionQuery);
401:
402: try {
403: f.setKeywords(new ArrayList(keywords));
404: } catch (Exception e) {
405: // do nothing, defaults already exist.
406: }
407:
408: try {
409: f.setMetadataLinks(new ArrayList(metadataLinks));
410: } catch (Exception e) {
411: // do nothing, defaults already exist.
412: }
413:
414: f.setDefaultStyle(defaultStyle);
415: f.setStyles(styles);
416: f.setDirName(dirName);
417: f.setSchemaBase(schemaBase);
418: f.setSchemaName(schemaName);
419:
420: f.setCachingEnabled(cachingEnabled);
421: f.setCacheMaxAge(cacheMaxAge);
422: f.setMaxFeatures(maxFeatures);
423:
424: return f;
425: }
426:
427: /**
428: * Searches through the schema looking for an AttributeTypeInfoConfig that
429: * matches the name passed in attributeTypeName
430: *
431: * @param attributeTypeName the name of the AttributeTypeInfo to search
432: * for.
433: *
434: * @return AttributeTypeInfoConfig from the schema, if found
435: */
436: public AttributeTypeInfoConfig getAttributeFromSchema(
437: String attributeTypeName) {
438: Iterator iter = schemaAttributes.iterator();
439:
440: while (iter.hasNext()) {
441: AttributeTypeInfoConfig atiConfig = (AttributeTypeInfoConfig) iter
442: .next();
443:
444: if (atiConfig.getName().equals(attributeTypeName)) {
445: return atiConfig;
446: }
447: }
448:
449: return null;
450: }
451:
452: /**
453: * Convience method for dataStoreId.typeName.
454: *
455: * <p>
456: * This key may be used to store this FeatureType in a Map for later.
457: * </p>
458: *
459: * @return dataStoreId.typeName
460: */
461: public String getKey() {
462: return getDataStoreId() + DataConfig.SEPARATOR + getName();
463: }
464:
465: /**
466: * Access _abstract property.
467: *
468: * @return Returns the _abstract.
469: */
470: public String getAbstract() {
471: return _abstract;
472: }
473:
474: /**
475: * Set _abstract to _abstract.
476: *
477: * @param _abstract The _abstract to set.
478: */
479: public void setAbstract(String _abstract) {
480: this ._abstract = _abstract;
481: }
482:
483: /**
484: * Access dataStoreId property.
485: *
486: * @return Returns the dataStoreId.
487: */
488: public String getDataStoreId() {
489: return dataStoreId;
490: }
491:
492: /**
493: * Set dataStoreId to dataStoreId.
494: *
495: * @param dataStoreId The dataStoreId to set.
496: */
497: public void setDataStoreId(String dataStoreId) {
498: this .dataStoreId = dataStoreId;
499: }
500:
501: /**
502: * Access defaultStyle property.
503: *
504: * @return Returns the defaultStyle.
505: */
506: public String getDefaultStyle() {
507: return defaultStyle;
508: }
509:
510: /**
511: * Set defaultStyle to defaultStyle.
512: *
513: * @param defaultStyle The defaultStyle to set.
514: */
515: public void setDefaultStyle(String defaultStyle) {
516: this .defaultStyle = defaultStyle;
517: }
518:
519: public ArrayList getStyles() {
520: return styles;
521: }
522:
523: public void setStyles(ArrayList styles) {
524: this .styles = styles;
525: }
526:
527: public void addStyle(String style) {
528: if (!this .styles.contains(style)) {
529: this .styles.add(style);
530: }
531: }
532:
533: /**
534: * Access definitionQuery property.
535: *
536: * @return Returns the definitionQuery.
537: */
538: public Filter getDefinitionQuery() {
539: return definitionQuery;
540: }
541:
542: /**
543: * Set definitionQuery to definitionQuery.
544: *
545: * @param definitionQuery The definitionQuery to set.
546: */
547: public void setDefinitionQuery(Filter definitionQuery) {
548: this .definitionQuery = definitionQuery;
549: }
550:
551: /**
552: * Access dirName property.
553: *
554: * @return Returns the dirName.
555: */
556: public String getDirName() {
557: return dirName;
558: }
559:
560: /**
561: * Set dirName to dirName.
562: *
563: * @param dirName The dirName to set.
564: */
565: public void setDirName(String dirName) {
566: this .dirName = dirName;
567: }
568:
569: /**
570: * Access keywords property.
571: *
572: * @return Returns the keywords.
573: */
574: public Set getKeywords() {
575: return keywords;
576: }
577:
578: /**
579: * Set keywords to keywords.
580: *
581: * @param keywords The keywords to set.
582: */
583: public void setKeywords(Set keywords) {
584: this .keywords = keywords;
585: }
586:
587: /**
588: * Access metadataURLs property.
589: *
590: * @return Returns the metadataURLs.
591: */
592: public Set getMetadataLinks() {
593: return metadataLinks;
594: }
595:
596: /**
597: * Set metadataURLs to metadataURLs.
598: *
599: * @param metadataURLs The metadataURLs to set.
600: */
601: public void setMetadataLinks(Set metadataURLs) {
602: this .metadataLinks = metadataURLs;
603: }
604:
605: /**
606: * Access latLongBBox property.
607: *
608: * @return Returns the latLongBBox.
609: */
610: public Envelope getLatLongBBox() {
611: return latLongBBox;
612: }
613:
614: /**
615: * Set latLongBBox to latLongBBox.
616: *
617: * @param latLongBBox The latLongBBox to set.
618: */
619: public void setLatLongBBox(Envelope latLongBBox) {
620: this .latLongBBox = latLongBBox;
621: }
622:
623: /**
624: * Access nativeBBox property.
625: *
626: * @return Returns the nativeBBox.
627: */
628: public Envelope getNativeBBox() {
629: return nativeBBox;
630: }
631:
632: /**
633: * Set nativeBBox to nativeBBox.
634: *
635: * @param nativeBBox The nativeBBox to set.
636: */
637: public void setNativeBBox(Envelope nativeBBox) {
638: this .nativeBBox = nativeBBox;
639: }
640:
641: /**
642: * Access name property.
643: *
644: * @return Returns the name.
645: */
646: public String getName() {
647: return name;
648: }
649:
650: /**
651: * Set name to name.
652: *
653: * @param name The name to set.
654: */
655: public void setName(String name) {
656: this .name = name;
657: }
658:
659: /**
660: * Access numDecimals property.
661: *
662: * @return Returns the numDecimals.
663: */
664: public int getNumDecimals() {
665: return numDecimals;
666: }
667:
668: /**
669: * Set numDecimals to numDecimals.
670: *
671: * @param numDecimals The numDecimals to set.
672: */
673: public void setNumDecimals(int numDecimals) {
674: this .numDecimals = numDecimals;
675: }
676:
677: /**
678: * Access schemaAttributes property.
679: *
680: * @return Returns the schemaAttributes.
681: */
682: public List getSchemaAttributes() {
683: return schemaAttributes;
684: }
685:
686: /**
687: * Set schemaAttributes to schemaAttributes.
688: *
689: * @param schemaAttributes The schemaAttributes to set.
690: */
691: public void setSchemaAttributes(List schemaAttributes) {
692: this .schemaAttributes = schemaAttributes;
693: }
694:
695: /**
696: * Access schemaBase property.
697: *
698: * @return Returns the schemaBase.
699: */
700: public String getSchemaBase() {
701: return schemaBase;
702: }
703:
704: /**
705: * Set schemaBase to schemaBase.
706: *
707: * @param schemaBase The schemaBase to set.
708: */
709: public void setSchemaBase(String schemaBase) {
710: this .schemaBase = schemaBase;
711: }
712:
713: /**
714: * Access schemaName property.
715: *
716: * @return Returns the schemaName.
717: */
718: public String getSchemaName() {
719: return schemaName;
720: }
721:
722: /**
723: * Set schemaName to schemaName.
724: *
725: * @param schemaName The schemaName to set.
726: */
727: public void setSchemaName(String schemaName) {
728: this .schemaName = schemaName;
729: }
730:
731: /**
732: * Access sRS property.
733: *
734: * @return Returns the sRS.
735: */
736: public int getSRS() {
737: return SRS;
738: }
739:
740: /**
741: * Set sRS to srs.
742: *
743: * @param srs The sRS to set.
744: */
745: public void setSRS(int srs) {
746: SRS = srs;
747: }
748:
749: public int getSRSHandling() {
750: return SRSHandling;
751: }
752:
753: public void setSRSHandling(int srsHandling) {
754: this .SRSHandling = srsHandling;
755: }
756:
757: /**
758: * Access title property.
759: *
760: * @return Returns the title.
761: */
762: public String getTitle() {
763: return title;
764: }
765:
766: /**
767: * Set title to title.
768: *
769: * @param title The title to set.
770: */
771: public void setTitle(String title) {
772: this .title = title;
773: }
774:
775: public String toString() {
776: return "FeatureTypeConfig[name: " + name + " alias: " + alias
777: + " schemaName: " + schemaName + " SRS: " + SRS
778: + " schemaAttributes: " + schemaAttributes
779: + " schemaBase " + schemaBase + "]";
780: }
781:
782: public String getWmsPath() {
783: return wmsPath;
784: }
785:
786: public void setWmsPath(String wmsPath) {
787: this .wmsPath = wmsPath;
788: }
789:
790: public boolean isCachingEnabled() {
791: return cachingEnabled;
792: }
793:
794: public void setCachingEnabled(boolean cachingEnabled) {
795: this .cachingEnabled = cachingEnabled;
796: }
797:
798: public String getCacheMaxAge() {
799: return cacheMaxAge;
800: }
801:
802: public void setCacheMaxAge(String cacheMaxAge) {
803: this .cacheMaxAge = cacheMaxAge;
804: }
805:
806: public int getMaxFeatures() {
807: return maxFeatures;
808: }
809:
810: public void setMaxFeatures(int maxFeatures) {
811: this .maxFeatures = maxFeatures;
812: }
813:
814: public String getAlias() {
815: return alias;
816: }
817:
818: public void setAlias(String alias) {
819: this.alias = alias;
820: }
821: }
|