/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-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.data; import java.io.IOException; import java.util.NoSuchElementException; import org.geotools.feature.FeatureTypes; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.resources.Classes; import org.opengis.feature.IllegalAttributeException; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; /** * Supports on the fly retyping of FeatureReader contents. *

* This may be used to have a DataStore work with your own representation of * Feature information. *

*

* Example Use: *

*

 *  FeatureReader reader = dataStore.getFeatureReader( query, Transaction.AUTO_COMMIT );
 * reader = new ReTypeFeatureReader( reader, myFeatureType );
 * try {
 *   while( reader.hasNext() ){
 *     Feature f = reader.next();
 *     System.out.println( f );
 *   }
 * }
 * finally {
 *   reader.close(); // will close both
 * } 
 * 
*

* This Reader makes a simple one to one between the original schema and the target schema based * on descriptor name. * * @author Jody Garnett (Refractions Research) * @source $URL$ */ public class ReTypeFeatureReader implements DelegatingFeatureReader { /** The original reader we are grabbing content from */ FeatureReader reader; /** This is the target feature type we are preparing data for */ SimpleFeatureType featureType; /** The descriptors we are going to from the original reader */ AttributeDescriptor[] types; /** Creates retyped features */ SimpleFeatureBuilder builder; boolean clone; /** * Constructs a FetureReader that will ReType streaming content. * * @param reader Origional FeatureReader * @param featureType Target FeatureType */ public ReTypeFeatureReader(FeatureReader reader, SimpleFeatureType featureType) { this(reader, featureType, true); } /** * Constructs a FetureReader that will ReType streaming content. * * @param reader Original FeatureReader * @param featureType Target FeatureType * @param clone true to clone the content * @since 2.3 */ public ReTypeFeatureReader(FeatureReader reader, SimpleFeatureType featureType, boolean clone) { this.reader = reader; this.featureType = featureType; this.clone = clone; types = typeAttributes(featureType, reader.getFeatureType()); builder = new SimpleFeatureBuilder(featureType); } public FeatureReader getDelegate() { return reader; } /** * Supplies mapping from original to target FeatureType. * *

* Will also ensure that mapping results in a valid selection of values * from the original. Only the xpath expression and binding are checked. *

* * @param target Desired FeatureType * @param origional Original FeatureType * * @return Mapping from originoal to target FeatureType * * @throws IllegalArgumentException if unable to provide a mapping */ protected AttributeDescriptor[] typeAttributes(SimpleFeatureType target, SimpleFeatureType origional) { if (FeatureTypes.equalsExact(origional, target)) { throw new IllegalArgumentException( "FeatureReader allready produces contents with the correct schema"); } if (target.getAttributeCount() > origional.getAttributeCount()) { throw new IllegalArgumentException( "Unable to retype FeatureReader (origional does not cover requested type)"); } String xpath; AttributeDescriptor[] types = new AttributeDescriptor[target.getAttributeCount()]; for (int i = 0; i < target.getAttributeCount(); i++) { AttributeDescriptor attrib = target.getDescriptor(i); xpath = attrib.getLocalName(); types[i] = attrib; AttributeDescriptor check = origional.getDescriptor( xpath ); Class targetBinding = attrib.getType().getBinding(); Class checkBinding = check.getType().getBinding(); if( !targetBinding.isAssignableFrom( checkBinding )){ throw new IllegalArgumentException( "Unable to retype FeatureReader for " + xpath + " as "+Classes.getShortName(checkBinding) + " cannot be assigned to "+Classes.getShortName(targetBinding) ); } } return types; } /** * @see org.geotools.data.FeatureReader#getFeatureType() */ public SimpleFeatureType getFeatureType() { return featureType; } /** * @see org.geotools.data.FeatureReader#next() */ public SimpleFeature next() throws IOException, IllegalAttributeException, NoSuchElementException { if (reader == null) { throw new IOException("FeatureReader has been closed"); } SimpleFeature next = reader.next(); String id = next.getID(); String xpath; for (int i = 0; i < types.length; i++) { xpath = types[i].getLocalName(); if(clone) builder.add(DataUtilities.duplicate(next.getAttribute(xpath))); else builder.add(next.getAttribute(xpath)); } return builder.buildFeature(id); } /** * @see org.geotools.data.FeatureReader#hasNext() */ public boolean hasNext() throws IOException { return reader.hasNext(); } /** * @see org.geotools.data.FeatureReader#close() */ public void close() throws IOException { if (reader != null) { reader.close(); reader = null; featureType = null; types = null; } } }