/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.feature;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import org.geotools.feature.type.AttributeDescriptorImpl;
import org.opengis.feature.ComplexAttribute;
import org.opengis.feature.Property;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.ComplexType;
import org.opengis.feature.type.Name;
import org.opengis.filter.identity.Identifier;
public class ComplexAttributeImpl extends AttributeImpl implements ComplexAttribute {
public ComplexAttributeImpl(Collection<Property> properties, AttributeDescriptor descriptor, Identifier id) {
super(cloneProperties( properties ), descriptor, id );
}
public ComplexAttributeImpl(Collection<Property> properties, ComplexType type, Identifier id) {
this(properties, new AttributeDescriptorImpl( type, type.getName(), 1, 1, true, null), id);
}
public ComplexType getType() {
return (ComplexType) super.getType();
}
public Collection<? extends Property> getValue() {
return FeatureImplUtils.unmodifiable((Collection) super.getValue());
}
public Collection<Property> getProperties() {
return FeatureImplUtils.unmodifiable((Collection) super.getValue());
}
/**
* Internal helper method for getting at the properties without wrapping
* in unmodifiable collection.
*/
protected Collection properties() {
return (Collection) super.getValue();
}
public Collection<Property> getProperties(Name name) {
List<Property> matches = new ArrayList<Property>();
for ( Iterator p = getValue().iterator(); p.hasNext(); ) {
Property property = (Property) p.next();
if ( property.getName().equals( name ) ) {
matches.add( property );
}
}
return matches;
}
public Collection<Property> getProperties(String name) {
List<Property> matches = new ArrayList<Property>();
for ( Iterator p = properties().iterator(); p.hasNext(); ) {
Property property = (Property) p.next();
if ( property.getName().getLocalPart().equals( name ) ) {
matches.add( property );
}
}
return matches;
}
public Property getProperty(Name name) {
for ( Iterator p = properties().iterator(); p.hasNext(); ) {
Property property = (Property) p.next();
if ( property.getName().equals( name ) ) {
return property;
}
}
return null;
}
public Property getProperty(String name) {
for ( Iterator p = getValue().iterator(); p.hasNext(); ) {
Property property = (Property) p.next();
if ( property.getName().getLocalPart().equals( name ) ) {
return property;
}
}
return null;
}
public void setValue(Object newValue) throws IllegalArgumentException,
IllegalStateException {
setValue((Collection<Property>)newValue);
}
public void setValue(Collection<Property> newValue) {
super.setValue(cloneProperties(newValue));
}
/**
* helper method to clone the property collection.
*/
private static Collection cloneProperties( Collection original ) {
if ( original == null ) {
return null;
}
Collection clone = null;
try {
clone = original.getClass().newInstance();
}
catch( Exception e ) {
clone = new ArrayList();
}
clone.addAll( original );
return clone;
}
// public List/* <Property> */get(Name name) {
// // JD: this is a farily lenient check, should we be stricter about
// // matching up the namespace
// List/* <Property> */childs = new LinkedList/* <Property> */();
//
// for (Iterator itr = this.properties.iterator(); itr.hasNext();) {
// Property prop = (Property) itr.next();
// PropertyDescriptor node = prop.descriptor();
// Name propName = node.getName();
// if (name.getNamespaceURI() != null) {
// if (propName.equals(name)) {
// childs.add(prop);
// }
// } else {
// // just do a local part compare
// String localName = propName.getLocalPart();
// if (localName.equals(name.getLocalPart())) {
// childs.add(prop);
// }
// }
//
// }
// return childs;
// }
//
// /**
// * Represents just enough info to convey the idea of this being a "view"
// * into getAttribtues.
// */
// protected synchronized List/* <AttributeType> */types() {
// if (types == null) {
// types = createTypesView((List) getValue());
// }
// return types;
// }
//
// /** Factory method so subclasses can optimize */
// protected List/* <AttributeType> */createTypesView(
// final List/* <Attribute> */source) {
// if (source == null)
// return Collections.EMPTY_LIST;
//
// return new AbstractList/* <AttributeType> */() {
// // @Override
// public Object /* AttributeType */get(int index) {
// return ((Attribute) source.get(index)).getType();
// }
//
// // @Override
// public int size() {
// return source.size();
// }
//
// // @Override
// public Object /* AttributeType */remove(int index) {
// Attribute removed = (Attribute) source.remove(index);
// if (removed != null) {
// return removed.getType();
// }
// return null;
// }
//
// /**
// * Unsupported.
// * <p>
// * We may be able to do this for nilable types, or types that have a
// * default value.
// * </p>
// *
// * @param index
// * @param type
// */
// // @Override
// public void add(int index, Object o) {
// throw new UnsupportedOperationException(
// "Cannot add directly to types");
// }
// };
// }
//
// public synchronized List/* <Object> */values() {
// if (values == null) {
// values = createValuesView((List) getValue());
// }
// return values;
// }
//
// /** Factory method so subclasses can optimize */
// protected List/* <Object> */createValuesView(
// final List/* <Attribute> */source) {
// return new AbstractList/* <Object> */() {
// // @Override
// public Object get(int index) {
// return ((Attribute) source.get(index)).getValue();
// }
//
// // @Override
// public Object set(int index, Object value) {
// Object replaced = ((Attribute) source.get(index)).getValue();
// ((Attribute) source.get(index)).setValue(value);
// return replaced;
// }
//
// // @Override
// public int size() {
// return source.size();
// }
//
// // @Override
// public Object /* AttributeType */remove(int index) {
// Attribute removed = (Attribute) source.remove(index);
// if (removed != null) {
// return removed.getValue();
// }
// return null;
// }
//
// /**
// * Unsupported, we can support this for flat schema.
// * <p>
// * We may be able to do this after walking the schema and figuring
// * out that there is only one binding for the provided object.
// * </p>
// *
// * @param index
// * @param testType
// */
// // @Override
// public void add(int index, Object value) {
// throw new UnsupportedOperationException(
// "Cannot add directly to values");
// }
// };
// }
//
// public void setValue(Object newValue) {
//
// if (newValue == null) {
// properties.clear();
// } else {
// properties = new ArrayList( (Collection) newValue );
// }
//
// // reset "views"
// attributes = null;
// associations = null;
// types = null;
// values = null;
// }
//
// protected Object get(AttributeType type) {
// if (type == null) {
// throw new NullPointerException("type");
// }
//
// // JD: Is this crazy or is it just me? This method returns an object
// // in one case, and collection in the other?
// ComplexType ctype = TYPE;
// if (Descriptors.multiple(ctype, type)) {
// List/* <Object> */got = new ArrayList/* <Object> */();
// for (Iterator itr = properties.iterator(); itr.hasNext();) {
// Attribute attribute = (Attribute) itr.next();
// if (attribute.getType().equals(type)) {
// got.add(attribute.getValue());
// }
// }
// return got;
// } else {
// for (Iterator itr = properties.iterator(); itr.hasNext();) {
// Attribute attribute = (Attribute) itr.next();
// if (attribute.getType().equals(type)) {
// return attribute.getValue();
// }
// }
// return null;
// }
// }
//
// public boolean equals(Object o) {
// if (!(o instanceof ComplexAttributeImpl)) {
// return false;
// }
// ComplexAttributeImpl c = (ComplexAttributeImpl) o;
//
// if (!Utilities.equals(ID, c.ID))
// return false;
//
// if (!Utilities.equals(TYPE, c.TYPE))
// return false;
//
// if (!Utilities.equals(DESCRIPTOR, c.DESCRIPTOR)) {
// return false;
// }
//
// return this.properties.equals(c.properties);
// }
//
// public int hashCode() {
// if (HASHCODE == -1) {
// HASHCODE = 23 + (TYPE == null ? 1 : TYPE.hashCode())
// * (DESCRIPTOR == null ? 1 : DESCRIPTOR.hashCode())
// * properties.hashCode() * (ID == null ? 1 : ID.hashCode());
// }
// return HASHCODE;
// }
//
// public String toString() {
// StringBuffer sb = new StringBuffer(getClass().getName());
// List/* <Attribute> */atts = this.properties;
// sb.append("[id=").append(this.ID).append(", name=").append(
// DESCRIPTOR != null ? DESCRIPTOR.getName().toString() : "null")
// .append(", type=").append(getType().getName()).append('\n');
// for (Iterator itr = atts.iterator(); itr.hasNext();) {
// Attribute att = (Attribute) itr.next();
// sb.append(att);
// sb.append('\n');
// }
// sb.append("]");
// return sb.toString();
// }
//
// public Object operation(Name arg0, List arg1) {
// throw new UnsupportedOperationException("operation not supported yet");
// }
}