001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-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: package org.geotools.feature;
017:
018: import java.util.ArrayList;
019: import java.util.Iterator;
020: import java.util.List;
021:
022: import org.geotools.factory.CommonFactoryFinder;
023: import org.geotools.factory.Hints;
024: import org.opengis.filter.Filter;
025: import org.opengis.filter.FilterFactory;
026: import org.opengis.filter.PropertyIsNull;
027:
028: /**
029: * This class contains utility methods focused on the schema represented by
030: * the FeatureType data model.
031: * <p>
032: * These methods are often used for implementation the convience methods
033: * such as FeatureType.getAttributeCount(), although they may be used directly
034: * with any FeatureType.
035: * </p>
036: * <p>
037: * These schema methods are based on the *complete* picture indicated by a FeatureType
038: * and its ancestors. Many of these methods are focused on the derivation of AttribtueTypes
039: * during an override.
040: * </p>
041: * @see FeatureTypes
042: * @see FeatureType
043: * @author Jody Garnett
044: * @since 2.1.0
045: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/Schema.java $
046: */
047: public class Schema {
048: private static Schema DEFAULT = new Schema();
049: private FilterFactory ff;
050:
051: public Schema() {
052: this ((Hints) null);
053: }
054:
055: public Schema(Hints hints) {
056: this (CommonFactoryFinder.getFilterFactory(hints));
057: }
058:
059: public Schema(FilterFactory filterFactory) {
060: ff = filterFactory;
061: }
062:
063: /**
064: * Walk the provided FeatureType and produce a count of distinct attribtues.
065: * <p>
066: * used to detect duplicate attributes names (ie override)
067: * </p>
068: *
069: * @param featureType
070: */
071: public int getAttributeCount(FeatureType featureType) {
072: return getNames(featureType).size();
073: }
074:
075: /**
076: * Does a quick walk to detect only a list of attribute names.
077: * <p>
078: * This method does not produce the complete schema (ie derrived restrictions based
079: * on attribute facets). It is only used to get a list of the unique attribtues in
080: * the resulting schema.
081: * </p>
082: * @param featureType
083: *
084: * @return Set of unique attribute names
085: */
086: public List getNames(FeatureType featureType) {
087: return getNames(featureType, new ArrayList());
088: }
089:
090: /**
091: * This order is to be respected, based on Ancestors and so on.
092: * <p>
093: * This method is "faster" then actually constructing the merged
094: * AttribtueTypes.
095: * </p>
096: */
097: public List getNames(FeatureType featureType, List names) {
098: if (featureType == null
099: || featureType.getAttributeTypes() == null) {
100: return names;
101: }
102:
103: FeatureType ancestors[] = featureType.getAncestors();
104: if (ancestors != null && ancestors.length != 0) {
105: for (int i = 0, length = ancestors.length; i < length; i++) {
106: FeatureType super Type = ancestors[i];
107: getNames(super Type, names);
108: }
109: }
110: AttributeType attributes[] = featureType.getAttributeTypes();
111: if (attributes != null && attributes.length != 0) {
112: for (int i = 0, length = attributes.length; i < length; i++) {
113: AttributeType type = attributes[i];
114: String name = type.getName();
115: if (!names.contains(name)) {
116: names.add(name);
117: }
118: }
119: }
120: return names;
121: }
122:
123: public List getAttributes(FeatureType featureType) {
124: return getAttributes(featureType, new ArrayList());
125: }
126:
127: /**
128: * This order is to be respected, based on Ancestors and so on.
129: * <p>
130: * This method is "faster" then actually constructing the merged
131: * AttribtueTypes.
132: * </p>
133: */
134: public List getAttributes(FeatureType featureType, List list) {
135: if (featureType == null
136: || featureType.getAttributeTypes() == null) {
137: return list;
138: }
139:
140: FeatureType ancestors[] = featureType.getAncestors();
141: if (ancestors != null && ancestors.length != 0) {
142: for (int i = 0, length = ancestors.length; i < length; i++) {
143: //eatureType type = ancestors[i];
144: getAttributes(ancestors[i], list);
145: }
146: }
147: AttributeType attributes[] = featureType.getAttributeTypes();
148: if (attributes != null && attributes.length != 0) {
149: for (int i = 0, length = attributes.length; i < length; i++) {
150: AttributeType type = attributes[i];
151: String name = type.getName();
152: int index = getIndexOf(list, name);
153: if (index != -1) {
154: AttributeType origional = (AttributeType) list
155: .get(index);
156: list.remove(index);
157: list.add(index, override(origional, type));
158: } else {
159: list.add(type);
160: }
161: }
162: }
163: return list;
164: }
165:
166: /**
167: * Query featureType information the complete restrictions for the indicated name.
168: *
169: * @param featureType
170: * @param name
171: */
172: public Filter getRestrictions(FeatureType featureType, String name) {
173: if (featureType == null
174: || featureType.getAttributeTypes() == null)
175: return Filter.EXCLUDE;
176:
177: return restriction(featureType, name, Filter.INCLUDE);
178: }
179:
180: /**
181: * Lookup can only really be by name.
182: *
183: * @param type
184: */
185: public int getIndexOf(FeatureType type, String name) {
186: List names = getNames(type);
187: return names.indexOf(name);
188: }
189:
190: /**
191: * Look up based on name in the provided position.
192: *
193: * @param type the FeatureType
194: * @param index the position
195: *
196: */
197: public AttributeType getAttribute(FeatureType type, int index) {
198: String name = (String) getNames(type).get(index);
199: return getXPath(type, name);
200: }
201:
202: public AttributeType getAttribute(FeatureType type, String name) {
203: List list = getAttributes(type);
204: int index = getIndexOf(list, name);
205: if (index == -1)
206: return null;
207: return (AttributeType) list.get(index);
208: }
209:
210: /**
211: * Look up based on name in the provided position.
212: * <p>
213: * AttributeType needs a xpath based access
214: * </p>
215: * @param type
216: * @param xpath
217: *
218: */
219: public AttributeType getXPath(FeatureType type, String xpath) {
220: return getAttribute(type, xpath); // for now, use JXPath later
221: }
222:
223: // Utility Methods
224: //
225: private int getIndexOf(List attributes, String name) {
226: int index = 0;
227: for (Iterator i = attributes.iterator(); i.hasNext(); index++) {
228: AttributeType type = (AttributeType) i.next();
229: if (name.equals(type.getName()))
230: return index;
231: }
232: return -1;
233: }
234:
235: private AttributeType override(AttributeType type,
236: AttributeType override) {
237: int max = override.getMaxOccurs();
238: if (max < 0)
239: max = type.getMinOccurs();
240:
241: int min = override.getMinOccurs();
242: if (min < 0)
243: min = type.getMinOccurs();
244:
245: String name = override.getName();
246: if (name == null)
247: name = type.getName();
248:
249: Filter restriction = override(type.getRestriction(), override
250: .getRestriction());
251:
252: Class javaType = override.getType();
253: if (javaType == null)
254: javaType = type.getType();
255:
256: boolean isNilable = override.isNillable();
257:
258: Object defaultValue = override.createDefaultValue();
259: if (defaultValue == null)
260: defaultValue = type.createDefaultValue();
261:
262: // WARNING cannot copy metadata!
263: return AttributeTypeFactory.newAttributeType(name, javaType,
264: isNilable, restriction, defaultValue, null);
265: }
266:
267: private Filter restriction(FeatureType featureType, String name,
268: Filter filter) {
269: FeatureType ancestors[] = featureType.getAncestors();
270: if (ancestors != null && ancestors.length != 0) {
271: for (int i = 0, length = ancestors.length; i < length; i++) {
272: FeatureType super Type = ancestors[i];
273: filter = restriction(super Type, name, filter);
274: }
275: }
276: AttributeType attributes[] = featureType.getAttributeTypes();
277: if (attributes != null && attributes.length != 0) {
278: for (int i = 0, length = attributes.length; i < length; i++) {
279: AttributeType type = attributes[i];
280: if (name.equals(type.getName())) {
281: filter = override(filter, type.getRestriction());
282: }
283: }
284: }
285: return filter;
286: }
287:
288: private Filter override(Filter filter, Filter override) {
289: if (isNOP(override)) {
290: // no override is needed
291: return filter;
292: } else if (isNOP(filter)) {
293: return override;
294: } else {
295: return ff.and(filter, override);
296: }
297: }
298:
299: private boolean isNOP(Filter filter) {
300: return filter == null || filter instanceof PropertyIsNull
301: || filter == Filter.INCLUDE;
302: }
303:
304: // Utiltie Methods
305: // (make use of DEFAULT Schema)
306: //
307:
308: /**
309: * Walk the provided FeatureType and produce a count of distinct attribtues.
310: * <p>
311: * used to detect duplicate attributes names (ie override)
312: * </p>
313: *
314: * @param featureType
315: */
316: public static int attributeCount(FeatureType featureType) {
317: return DEFAULT.getAttributeCount(featureType);
318: }
319:
320: /**
321: * @deprecated use getAttribute( type, index )
322: */
323: public static AttributeType attribute(FeatureType type, int index) {
324: return DEFAULT.getAttribute(type, index);
325: }
326:
327: /** @deprecated use getAttribute( type, name ) */
328: public static AttributeType attribute(FeatureType type, String name) {
329: return DEFAULT.getAttribute(type, name);
330: }
331:
332: /** @deprecated use getAttributes( featureType ) */
333: public static List attributes(FeatureType featureType) {
334: return DEFAULT.getAttributes(featureType);
335: }
336:
337: /** @deprecated use getAttributes( featureType, list ) */
338: public static List attributes(FeatureType featureType, List list) {
339: return DEFAULT.getAttributes(featureType, list);
340: }
341:
342: /**
343: * @deprecated please use getIndexOf( type, name )
344: */
345: public static int find(FeatureType type, String name) {
346: return DEFAULT.getIndexOf(type, name);
347: }
348:
349: /**
350: * @deprecated use getNames( featureType )
351: */
352: public static List names(FeatureType featureType) {
353: return DEFAULT.getNames(featureType);
354: }
355:
356: /**
357: * @deprecated use getNames( featureType, List )
358: */
359: public static List names(FeatureType featureType, List names) {
360: return DEFAULT.getNames(featureType, names);
361: }
362:
363: /**
364: * @deprecated please use getRestriction( featureType, name )
365: */
366: public static Filter restriction(FeatureType featureType,
367: String name) {
368: return DEFAULT.getRestrictions(featureType, name);
369: }
370:
371: /**
372: * @deprecated use getXPath( type, xpath );
373: */
374: public static AttributeType xpath(FeatureType type, String xpath) {
375: return DEFAULT.getAttribute(type, xpath); // for now, use JXPath later
376: }
377: }
|