001: package org.geotools.feature.iso;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Iterator;
006: import java.util.List;
007: import java.util.logging.Logger;
008:
009: import org.geotools.feature.iso.type.AttributeDescriptorImpl;
010: import org.opengis.feature.Association;
011: import org.opengis.feature.Attribute;
012: import org.opengis.feature.ComplexAttribute;
013: import org.opengis.feature.Feature;
014: import org.opengis.feature.FeatureFactory;
015: import org.opengis.feature.GeometryAttribute;
016: import org.opengis.feature.Property;
017: import org.opengis.feature.type.AssociationDescriptor;
018: import org.opengis.feature.type.AttributeDescriptor;
019: import org.opengis.feature.type.AttributeType;
020: import org.opengis.feature.type.ComplexType;
021: import org.opengis.feature.type.FeatureCollectionType;
022: import org.opengis.feature.type.FeatureType;
023: import org.opengis.feature.type.GeometryType;
024: import org.opengis.feature.type.Name;
025: import org.opengis.feature.type.PropertyDescriptor;
026: import org.opengis.referencing.crs.CoordinateReferenceSystem;
027:
028: /**
029: * Builder for attributes.
030: *
031: * @author Justin Deoliveira, The Open Planning Project, jdeolive@openplans.org
032: *
033: */
034: public class AttributeBuilder {
035: private static final Logger LOGGER = org.geotools.util.logging.Logging
036: .getLogger(AttributeBuilder.class.getPackage().getName());
037:
038: /**
039: * Factory used to create attributes
040: */
041: FeatureFactory attributeFactory;
042:
043: /**
044: * Namespace context.
045: */
046: String namespace;
047:
048: /**
049: * Type of complex attribute being built.
050: * This field is mutually exclusive with {@link #descriptor}
051: */
052: AttributeType type;
053:
054: /**
055: * Descriptor of complex attribute being built.
056: * This field is mutually exclusive with {@link #type}
057: */
058: AttributeDescriptor descriptor;
059:
060: /**
061: * Contained properties (associations + attributes)
062: */
063: List properties;
064:
065: /**
066: * The crs of the attribute.
067: */
068: CoordinateReferenceSystem crs;
069:
070: /**
071: * Default geometry of the feature.
072: */
073: Object defaultGeometry;
074:
075: public AttributeBuilder(FeatureFactory attributeFactory) {
076: this .attributeFactory = attributeFactory;
077: }
078:
079: //
080: // Injection
081: //
082: // Used to inject dependencies we need during construction time.
083: //
084: /**
085: * Returns the underlying attribute factory.
086: */
087: public FeatureFactory getFeatureFactory() {
088: return attributeFactory;
089: }
090:
091: /**
092: * Sets the underlying attribute factory.
093: */
094: public void setFeatureFactory(FeatureFactory attributeFactory) {
095: this .attributeFactory = attributeFactory;
096: }
097:
098: //
099: // State
100: //
101:
102: /**
103: * Initializes the builder to its initial state, the same state it is in
104: * directly after being instantiated.
105: */
106: public void init() {
107: descriptor = null;
108: type = null;
109: properties = null;
110: crs = null;
111: defaultGeometry = null;
112: }
113:
114: /**
115: * Initializes the state of the builder based on a previously built
116: * attribute.
117: * <p>
118: * This method is useful when copying another attribute.
119: * </p>
120: */
121: public void init(Attribute attribute) {
122: init();
123:
124: descriptor = attribute.getDescriptor();
125: type = attribute.getType();
126:
127: if (attribute instanceof ComplexAttribute) {
128: ComplexAttribute complex = (ComplexAttribute) attribute;
129: Collection properties = (Collection) complex.getValue();
130: for (Iterator itr = properties.iterator(); itr.hasNext();) {
131: Property property = (Property) itr.next();
132: if (property instanceof Attribute) {
133: Attribute att = (Attribute) property;
134: add(att.getID(), att.getValue(), att.name());
135: } else if (property instanceof Association) {
136: Association assoc = (Association) property;
137: associate(assoc.getRelated(), assoc.name());
138: }
139: }
140: }
141:
142: if (attribute instanceof Feature) {
143: Feature feature = (Feature) attribute;
144: crs = feature.getCRS();
145:
146: if (feature.getDefaultGeometry() != null) {
147: defaultGeometry = feature.getDefaultGeometry()
148: .getValue();
149: }
150: }
151:
152: }
153:
154: /**
155: * This namespace will be used when constructing attribute names.
156: */
157: public void setNamespaceURI(String namespace) {
158: this .namespace = namespace;
159: }
160:
161: /**
162: * This namespace will be used when constructing attribute names.
163: *
164: * @return namespace will be used when constructing attribute names.
165: */
166: public String getNamespaceURI() {
167: return namespace;
168: }
169:
170: /**
171: * Sets the type of the attribute being built.
172: * <p>
173: * When building a complex attribute, this type is used a reference to
174: * obtain the types of contained attributes.
175: * </p>
176: */
177: public void setType(AttributeType type) {
178: this .type = type;
179: this .descriptor = null;
180: }
181:
182: /**
183: * Sets the descriptor of the attribute being built.
184: * <p>
185: * When building a complex attribute, this type is used a reference to
186: * obtain the types of contained attributes.
187: * </p>
188: */
189: public void setDescriptor(AttributeDescriptor descriptor) {
190: this .descriptor = descriptor;
191: this .type = (AttributeType) descriptor.type();
192: }
193:
194: /**
195: * @return The type of the attribute being built.
196: */
197: public AttributeType getType() {
198: return type;
199: }
200:
201: // Feature specific methods
202: /**
203: * Sets the coordinate reference system of the built feature.
204: */
205: public void setCRS(CoordinateReferenceSystem crs) {
206: this .crs = crs;
207: }
208:
209: /**
210: * @return The coordinate reference system of the feature, or null if not
211: * set.
212: */
213: public CoordinateReferenceSystem getCRS() {
214: return crs;
215: }
216:
217: /**
218: * Sets the default geometry of the feature.
219: */
220: public void setDefaultGeometry(Object defaultGeometry) {
221: this .defaultGeometry = defaultGeometry;
222: }
223:
224: /**
225: * @return The default geometry of the feature.
226: */
227: public Object getDefaultGeometry() {
228: return defaultGeometry;
229: }
230:
231: //
232: // Complex attribute specific methods
233: //
234: /**
235: * Adds an attribute to the complex attribute being built. <br>
236: * <p>
237: * This method uses the result of {@link #getNamespaceURI()} to build a
238: * qualified attribute name.
239: * </p>
240: * <p>
241: * This method uses the type supplied in {@link #setType(AttributeType)} in
242: * order to determine the attribute type.
243: * </p>
244: *
245: * @param name
246: * The name of the attribute.
247: * @param value
248: * The value of the attribute.
249: *
250: */
251: public Attribute add(Object value, String name) {
252: return add(null, value, name);
253: }
254:
255: /**
256: * Adds an association to the complex attribute being built. <br>
257: * <p>
258: * This method uses the result of {@link #getNamespaceURI()} to build a
259: * qualified attribute name.
260: * </p>
261: * <p>
262: * This method uses the type supplied in {@link #setType(AttributeType)} in
263: * order to determine the association type.
264: * </p>
265: *
266: * @param value
267: * The value of the association, an attribute.
268: * @param name
269: * The name of the association.
270: */
271: public void associate(Attribute value, String name) {
272: associate(value, name, namespace);
273: }
274:
275: /**
276: * Adds an attribute to the complex attribute being built. <br>
277: * <p>
278: * This method uses the type supplied in {@link #setType(AttributeType)} in
279: * order to determine the attribute type.
280: * </p>
281: *
282: * @param value
283: * The value of the attribute.
284: * @param name
285: * The name of the attribute.
286: * @param namespaceURI
287: * The namespace of the attribute.
288: */
289: public Attribute add(Object value, String name, String namespaceURI) {
290: return add(null, value, name, namespaceURI);
291: }
292:
293: /**
294: * Adds an association to the complex attribute being built. <br>
295: * <p>
296: * This method uses the type supplied in {@link #setType(AttributeType)} in
297: * order to determine the association type.
298: * </p>
299: *
300: * @param value
301: * The value of the association, an attribute.
302: * @param name
303: * The name of the association.
304: * @param namespaceURI
305: * The namespace of the association
306: */
307: public void associate(Attribute attribute, String name,
308: String namespaceURI) {
309: associate(attribute, Types.typeName(namespaceURI, name));
310: }
311:
312: /**
313: * Adds an attribute to the complex attribute being built overriding the
314: * type of the declared attribute descriptor by a subtype of it. <br>
315: * <p>
316: * This method uses the type supplied in {@link #setType(AttributeType)} in
317: * order to determine the attribute type.
318: * </p>
319: *
320: * @param id
321: * the attribtue id
322: * @param value
323: * The value of the attribute.
324: *
325: * @param name
326: * The name of the attribute.
327: * @param type
328: * the actual type of the attribute, which might be the same as
329: * the declared type for the given AttributeDescriptor or a
330: * derived type.
331: *
332: */
333: public Attribute add(final String id, final Object value,
334: final Name name, final AttributeType type) {
335: // existence check
336: AttributeDescriptor descriptor = attributeDescriptor(name, type);
337: AttributeType declaredType = (AttributeType) descriptor.type();
338: if (!declaredType.equals(type)) {
339: boolean argIsSubType = Types
340: .isSuperType(type, declaredType);
341: if (!argIsSubType) {
342: /*
343: * commented out since we got community schemas where the
344: * required instance type is not a subtype of the declared one
345: * throw new IllegalArgumentException(type.getName() + " is not
346: * a subtype of " + declaredType.getName());
347: */
348: LOGGER.fine("Adding attribute " + name + " of type "
349: + type.getName()
350: + " which is not a subtype of "
351: + declaredType.getName());
352: }
353: int minOccurs = descriptor.getMinOccurs();
354: int maxOccurs = descriptor.getMaxOccurs();
355: boolean nillable = descriptor.isNillable();
356: //TODO: handle default value
357: Object defaultValue = null;
358: descriptor = new AttributeDescriptorImpl(type, name,
359: minOccurs, maxOccurs, nillable, defaultValue);
360: }
361: Attribute attribute = create(value, null, descriptor, id);
362: properties().add(attribute);
363: return attribute;
364: }
365:
366: /**
367: * Adds an attribute to the complex attribute being built. <br>
368: * <p>
369: * This method uses the type supplied in {@link #setType(AttributeType)} in
370: * order to determine the attribute type.
371: * </p>
372: *
373: * @param name
374: * The name of the attribute.
375: * @param value
376: * The value of the attribute.
377: *
378: */
379: public Attribute add(Object value, Name name) {
380: return add(null, value, name);
381: }
382:
383: /**
384: * Adds an association to the complex attribute being built. <br>
385: * <p>
386: * This method uses the type supplied in {@link #setType(AttributeType)} in
387: * order to determine the association type.
388: * </p>
389: *
390: * @param value
391: * The value of the association, an attribute.
392: * @param name
393: * The name of the association.
394: * @param namespaceURI
395: * The namespace of the association
396: */
397: public void associate(Attribute value, Name name) {
398: AssociationDescriptor descriptor = associationDescriptor(name);
399: Association association = attributeFactory.createAssociation(
400: value, descriptor);
401:
402: properties().add(association);
403: }
404:
405: /**
406: * Adds an attribute to the complex attribute being built. <br>
407: * <p>
408: * The result of {@link #getNamespaceURI()} to build a qualified attribute
409: * name.
410: * </p>
411: * <p>
412: * This method uses the type supplied in {@link #setType(AttributeType)} in
413: * order to determine the attribute type.
414: * </p>
415: *
416: * @param id
417: * The id of the attribute.
418: * @param name
419: * The name of the attribute.
420: * @param value
421: * The value of the attribute.
422: */
423: public Attribute add(String id, Object value, String name) {
424: return add(id, value, name, namespace);
425: }
426:
427: /**
428: * Adds an attribute to the complex attribute being built. <br>
429: * <p>
430: * This method uses the type supplied in {@link #setType(AttributeType)} in
431: * order to determine the attribute type.
432: * </p>
433: *
434: * @param id
435: * The id of the attribute.
436: * @param value
437: * The value of the attribute.
438: * @param name
439: * The name of the attribute.
440: * @param namespaceURI
441: * The namespace of the attribute.
442: */
443: public Attribute add(String id, Object value, String name,
444: String namespaceURI) {
445: return add(id, value, Types.typeName(namespaceURI, name));
446: }
447:
448: /**
449: * Adds an attribute to the complex attribute being built. <br>
450: * <p>
451: * This method uses the type supplied in {@link #setType(AttributeType)} in
452: * order to determine the attribute type.
453: * </p>
454: *
455: * @param id
456: * The id of the attribute.
457: * @param name
458: * The name of the attribute.
459: * @param value
460: * The value of the attribute.
461: *
462: */
463: public Attribute add(String id, Object value, Name name) {
464: AttributeDescriptor descriptor = attributeDescriptor(name);
465: Attribute attribute = create(value, null, descriptor, id);
466: properties().add(attribute);
467: return attribute;
468: }
469:
470: /**
471: * Convenience accessor for properties list which does the null check.
472: */
473: protected List properties() {
474: if (properties == null) {
475: properties = new ArrayList();
476: }
477:
478: return properties;
479: }
480:
481: protected AssociationDescriptor associationDescriptor(Name name) {
482: PropertyDescriptor descriptor = Types.descriptor(
483: (ComplexType) type, name);
484:
485: if (descriptor == null) {
486: String msg = "Could not locate association: " + name
487: + " in type: " + type.getName();
488: throw new IllegalArgumentException(msg);
489: }
490:
491: if (!(descriptor instanceof AssociationDescriptor)) {
492: String msg = name + " references a non association";
493: throw new IllegalArgumentException(msg);
494: }
495:
496: return (AssociationDescriptor) descriptor;
497: }
498:
499: protected AttributeDescriptor attributeDescriptor(Name name) {
500: PropertyDescriptor descriptor = Types.descriptor(
501: (ComplexType) type, name);
502:
503: if (descriptor == null) {
504: String msg = "Could not locate attribute: " + name
505: + " in type: " + type.getName();
506: throw new IllegalArgumentException(msg);
507: }
508:
509: if (!(descriptor instanceof AttributeDescriptor)) {
510: String msg = name + " references a non attribute";
511: throw new IllegalArgumentException(msg);
512: }
513:
514: return (AttributeDescriptor) descriptor;
515: }
516:
517: protected AttributeDescriptor attributeDescriptor(Name name,
518: AttributeType actualType) {
519: PropertyDescriptor descriptor = Types.descriptor(
520: (ComplexType) type, name, actualType);
521:
522: if (descriptor == null) {
523: String msg = "Could not locate attribute: " + name
524: + " in type: " + type.getName();
525: throw new IllegalArgumentException(msg);
526: }
527:
528: if (!(descriptor instanceof AttributeDescriptor)) {
529: String msg = name + " references a non attribute";
530: throw new IllegalArgumentException(msg);
531: }
532:
533: return (AttributeDescriptor) descriptor;
534: }
535:
536: /**
537: * Factors out attribute creation code, needs to be called with either one
538: * of type or descriptor null.
539: */
540: protected Attribute create(Object value, AttributeType type,
541: AttributeDescriptor descriptor, String id) {
542: if (descriptor != null) {
543: type = (AttributeType) descriptor.type();
544: }
545: Attribute attribute = null;
546: if (type instanceof FeatureCollectionType) {
547: attribute = descriptor != null ? attributeFactory
548: .createFeatureCollection((Collection) value,
549: descriptor, id) : attributeFactory
550: .createFeatureCollection((Collection) value,
551: (FeatureCollectionType) type, id);
552: } else if (type instanceof FeatureType) {
553: attribute = descriptor != null ? attributeFactory
554: .createFeature((Collection) value, descriptor, id)
555: : attributeFactory.createFeature(
556: (Collection) value, (FeatureType) type, id);
557: } else if (type instanceof ComplexType) {
558: attribute = descriptor != null ? attributeFactory
559: .createComplexAttribute((Collection) value,
560: descriptor, id) : attributeFactory
561: .createComplexAttribute((Collection) value,
562: (ComplexType) type, id);
563: } else if (type instanceof GeometryType) {
564: attribute = attributeFactory.createGeometryAttribute(value,
565: descriptor, id, null);
566: } else {
567: attribute = attributeFactory.createAttribute(value,
568: descriptor, id);
569: }
570: return attribute;
571: }
572:
573: /**
574: * Builds the attribute.
575: * <p>
576: * The class of the attribute built is determined from its type set with
577: * {@link #setType(AttributeType)}.
578: * </p>
579: *
580: * @return The build attribute.
581: */
582: public Attribute build() {
583: return build(null);
584: }
585:
586: /**
587: * Builds the attribute.
588: * <p>
589: * The class of the attribute built is determined from its type set with
590: * {@link #setType(AttributeType)}.
591: * </p>
592: *
593: * @param id
594: * The id of the attribute, or null.
595: *
596: * @return The build attribute.
597: */
598: public Attribute build(String id) {
599: Attribute built = create(properties(), type, descriptor, id);
600:
601: // if geometry, set the crs
602: if (built instanceof GeometryAttribute) {
603: ((GeometryAttribute) built).setCRS(getCRS());
604: }
605:
606: // if feature, set crs and default geometry
607: if (built instanceof Feature) {
608: Feature feature = (Feature) built;
609: feature.setCRS(getCRS());
610: if (defaultGeometry != null) {
611: for (Iterator itr = feature.attributes().iterator(); itr
612: .hasNext();) {
613: Attribute att = (Attribute) itr.next();
614: if (att instanceof GeometryAttribute) {
615: if (defaultGeometry.equals(att.getValue())) {
616: feature
617: .setDefaultGeometry((GeometryAttribute) att);
618: }
619: }
620:
621: }
622: }
623: }
624:
625: properties().clear();
626: return built;
627: }
628: }
|