/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2011, 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.jdbc; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.NoSuchElementException; import org.geotools.factory.Hints; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.jdbc.JoinInfo.JoinPart; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; /** * Feature reader that wraps multiple feature readers in a join query. * * @author Justin Deoliveira, OpenGeo * */ public class JDBCJoiningFeatureReader extends JDBCFeatureReader { List<JDBCFeatureReader> joinReaders; SimpleFeatureBuilder joinFeatureBuilder; public JDBCJoiningFeatureReader(String sql, Connection cx, JDBCFeatureSource featureSource, SimpleFeatureType featureType, JoinInfo join, Hints hints) throws SQLException, IOException { //super(sql, cx, featureSource, retype(featureType, join), hints); super(sql, cx, featureSource, featureType, hints); init(cx, featureSource, featureType, join, hints); } public JDBCJoiningFeatureReader(PreparedStatement st, Connection cx, JDBCFeatureSource featureSource, SimpleFeatureType featureType, JoinInfo join, Hints hints) throws SQLException, IOException { super(st, cx, featureSource, featureType, hints); init(cx, featureSource, featureType, join, hints); } void init(Connection cx, JDBCFeatureSource featureSource, SimpleFeatureType featureType, JoinInfo join, Hints hints) throws SQLException, IOException { joinReaders = new ArrayList<JDBCFeatureReader>(); int offset = featureType.getAttributeCount() + getPrimaryKey().getColumns().size(); for (JoinPart part : join.getParts()) { SimpleFeatureType ft = part.getQueryFeatureType(); joinReaders.add(new JDBCFeatureReader(rs, cx, offset, featureSource.getDataStore().getAbsoluteFeatureSource(ft.getTypeName()), ft, hints)); } //builder for the final joined feature joinFeatureBuilder = new SimpleFeatureBuilder(retype(featureType, join)); } @Override public boolean hasNext() throws IOException { boolean next = super.hasNext(); for (JDBCFeatureReader r : joinReaders) { r.setNext(next); } return next; } @Override public SimpleFeature next() throws IOException, IllegalArgumentException, NoSuchElementException { //read the regular feature SimpleFeature f = super.next(); //rebuild it with the join feature type joinFeatureBuilder.init(f); f = joinFeatureBuilder.buildFeature(f.getID()); //add additional attributes for joined features for (int i = 0; i < joinReaders.size(); i++) { JDBCFeatureReader r = joinReaders.get(i); f.setAttribute(f.getAttributeCount() - joinReaders.size() + i, r.next()); } return f; } @Override public void close() throws IOException { super.close(); //we don't need to close the delegate readers because they share the same result set // and connection as this reader } static SimpleFeatureType retype(SimpleFeatureType featureType, JoinInfo join) { SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder(); b.init(featureType); for (JoinPart part : join.getParts()) { b.add(part.getAttributeName(), SimpleFeature.class); } return b.buildFeatureType(); } }