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.type;
017:
018: import java.util.HashSet;
019: import java.util.Set;
020:
021: import org.geotools.feature.AttributeType;
022: import org.geotools.feature.IllegalAttributeException;
023: import org.opengis.filter.Filter;
024:
025: /**
026: * Represents an un-ordered Set of AttributeTypes. For SFS this should not be used.
027: * For GML this is the same as an element whose complexType contains a
028: * All of Attributes.
029: *
030: * NOTE: Some of the methods in this class has nasty order-dependant assumptions, please fix.
031: *
032: * @author dzwiers
033: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/type/SetAttributeType.java $
034: */
035: public class SetAttributeType implements AttributeType {
036:
037: private final boolean nill;
038: private final int min, max;
039: private final String name;
040: private final AttributeType[] children;
041: private Filter restriction;
042:
043: /**
044: * @param copy
045: */
046: public SetAttributeType(SetAttributeType copy) {
047: nill = copy.isNillable();
048: min = copy.getMinOccurs();
049: max = copy.getMaxOccurs();
050: name = copy.getName();
051: children = copy.getAttributeTypes();
052: restriction = copy.getRestriction();
053: }
054:
055: // The field for 'Class type' should be added when GT has moved to java 1.5
056: public SetAttributeType(String name, boolean nillable, int min,
057: int max, AttributeType[] children, Filter restriction) {
058: nill = nillable;
059: this .min = min;
060: this .max = max;
061: this .name = name;
062: this .children = children;
063: this .restriction = restriction;
064: }
065:
066: public SetAttributeType(String name, boolean nillable,
067: AttributeType[] children) {
068: this (name, nillable, 1, 1, children, Filter.EXCLUDE);
069: }
070:
071: public Filter getRestriction() {
072: return restriction;
073: }
074:
075: /* (non-Javadoc)
076: * @see org.geotools.feature.AttributeType#getName()
077: */
078: public String getName() {
079: return getLocalName();
080: }
081:
082: /**
083: * {@inheritDoc}
084: */
085: public String getLocalName() {
086: return name;
087: }
088:
089: /* (non-Javadoc)
090: * @see org.geotools.feature.AttributeType#getType()
091: */
092: public final Class getType() {
093: return getBinding();
094: }
095:
096: /**
097: * {@inheritDoc}
098: */
099: public Class getBinding() {
100: // The field for 'Class type' should be added when GT has moved to java 1.5
101: return Set.class;
102: }
103:
104: /* (non-Javadoc)
105: * @see org.geotools.feature.AttributeType#isNillable()
106: */
107: public boolean isNillable() {
108: return nill;
109: }
110:
111: /* (non-Javadoc)
112: * @see org.geotools.feature.AttributeType#getMinOccurs()
113: */
114: public int getMinOccurs() {
115: return min;
116: }
117:
118: /* (non-Javadoc)
119: * @see org.geotools.feature.AttributeType#getMaxOccurs()
120: */
121: public int getMaxOccurs() {
122: return max;
123: }
124:
125: /* (non-Javadoc)
126: * @see org.geotools.feature.AttributeType#isGeometry()
127: */
128: public boolean isGeometry() {
129: return false;
130: }
131:
132: /**
133: * This method is unstable ... and does not yet check validity well.
134: * TODO make this method robust
135: *
136: * This method assumes the Objects are in the order of the attributes.
137: * In the future, this should be implemented with a bubble sort type
138: * algorithm for testing each object vs each child. Bubble sort is
139: * recommended as the sample size is typically less than 25 elements,
140: * and the operation takes O(n*n) time.
141: */
142: public Object parse(Object value) throws IllegalArgumentException {
143: if (value instanceof Set) {
144: Object[] in;
145: in = ((Set) value).toArray();
146: Set out = new HashSet(in.length);
147: if (in.length == children.length) {
148: for (int i = 0; i < children.length; i++) {
149: out.add(children[i].parse(in[i]));
150: }
151: return out;
152: }
153: throw new IllegalArgumentException("Expected "
154: + children.length + " Objects, got " + in.length
155: + " Objects");
156: }
157: throw new IllegalArgumentException("Not an Object []");
158: }
159:
160: /**
161: * This method is unstable ... and does not yet check validity well.
162: * TODO make this method robust
163: *
164: * This method assumes the Objects are in the order of the attributes.
165: * In the future, this should be implemented with a bubble sort type
166: * algorithm for testing each object vs each child. Bubble sort is
167: * recommended as the sample size is typically less than 25 elements,
168: * and the operation takes O(n*n) time.
169: *
170: * Note that on the Attribute side of the fence ... this is acutally
171: * an unordered List (a Set of elements, where each element has multiplicity ...)
172: */
173: public void validate(Object obj) throws IllegalArgumentException {
174: if (obj instanceof Set) {
175: Object[] in;
176: in = ((Set) obj).toArray();
177: if (in.length == children.length) {
178: for (int i = 0; i < children.length; i++) {
179: children[i].validate(in[i]);
180: }
181: return;
182: }
183: throw new IllegalArgumentException("Expected "
184: + children.length + " Objects, got " + in.length
185: + " Objects");
186: }
187: throw new IllegalArgumentException("Not an Object []");
188:
189: }
190:
191: /**
192: * This method is unstable ... and does not yet check validity well.
193: * TODO make this method robust
194: *
195: * This method assumes the Objects are in the order of the attributes.
196: * In the future, this should be implemented with a bubble sort type
197: * algorithm for testing each object vs each child. Bubble sort is
198: * recommended as the sample size is typically less than 25 elements,
199: * and the operation takes O(n*n) time.
200: */
201: public Object duplicate(Object src)
202: throws IllegalAttributeException {
203: if (src instanceof Set) {
204: Object[] in;
205: in = ((Set) src).toArray();
206: Set out = new HashSet(in.length);
207: if (in.length == children.length) {
208: for (int i = 0; i < children.length; i++) {
209: out.add(children[i].duplicate(in[i]));
210: }
211: return out;
212: }
213: throw new IllegalArgumentException("Expected "
214: + children.length + " Objects, got " + in.length
215: + " Objects");
216: }
217: throw new IllegalArgumentException("Not an Object []");
218: }
219:
220: /**
221: * This method is unstable ... and does not yet check validity well.
222: * TODO make this method robust
223: *
224: * This method assumes the Objects are in the order of the attributes.
225: * In the future, this should be implemented with a bubble sort type
226: * algorithm for testing each object vs each child. Bubble sort is
227: * recommended as the sample size is typically less than 25 elements,
228: * and the operation takes O(n*n) time.
229: */
230: public Object createDefaultValue() {
231: Set out = new HashSet(children.length);
232: for (int i = 0; i < children.length; i++) {
233: out.add(children[i].createDefaultValue());
234: }
235: return out;
236: }
237:
238: /**
239: * This is only used twice in the whole geotools code base, and one of
240: * those is for a test, so we're removing it from the interface. If
241: * getAttributeType does not have the AttributeType it will just return
242: * null. Gets the number of occurrences of this attribute.
243: *
244: * @param xPath XPath pointer to attribute type.
245: *
246: * @return Number of occurrences.
247: */
248: public boolean hasAttributeType(String xPath) {
249: return getAttributeType(xPath) != null;
250: }
251:
252: /**
253: * Returns the number of attributes at the first 'level' of the schema.
254: *
255: * @return equivalent value to getAttributeTypes().length
256: */
257: public int getAttributeCount() {
258: return children.length;
259: }
260:
261: /**
262: * Gets the attributeType at this xPath, if the specified attributeType
263: * does not exist then null is returned.
264: *
265: * @param xPath XPath pointer to attribute type.
266: *
267: * @return True if attribute exists.
268: */
269: public AttributeType getAttributeType(String xPath) {
270: AttributeType attType = null;
271: int idx = find(xPath);
272: if (idx >= 0)
273: attType = children[idx];
274: return attType;
275: }
276:
277: /**
278: * Find the position of a given AttributeType.
279: *
280: * @param type The type to search for.
281: *
282: * @return -1 if not found, a zero-based index if found.
283: */
284: public int find(AttributeType type) {
285: if (type == null)
286: return -1;
287: int idx = find(type.getName());
288: if (idx < 0 || !children[idx].equals(type))
289: idx = -1;
290: return idx;
291: }
292:
293: /**
294: * Find the position of an AttributeType which matches the given String.
295: * @param attName the name to look for
296: * @return -1 if not found, zero-based index otherwise
297: */
298: public int find(String attName) {
299: int i = 0;
300: while (i < children.length
301: && !attName.equals(children[i].getName()))
302: i++;
303: return i == children.length ? -1 : i;
304: }
305:
306: /**
307: * Gets the attributeType at the specified index.
308: *
309: * @param position the position of the attribute to check.
310: *
311: * @return The attribute type at the specified position.
312: */
313: public AttributeType getAttributeType(int position) {
314: return children[position];
315: }
316:
317: public AttributeType[] getAttributeTypes() {
318: return (AttributeType[]) children.clone();
319: }
320: }
|