/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-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.sort; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.RandomAccessFile; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import org.opengis.feature.type.AttributeDescriptor; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKBReader; /** * Reads the features stored in the specified block of a {@link RandomAccessFile} * * @author Andrea Aime - GeoSolutions */ class FeatureBlockReader { RandomAccessFile raf; SimpleFeatureType schema; SimpleFeatureBuilder builder; SimpleFeature curr; long offset; int count; public FeatureBlockReader(RandomAccessFile raf, long start, int count, SimpleFeatureType schema) { this.raf = raf; this.offset = start; this.count = count; this.schema = schema; this.builder = new SimpleFeatureBuilder(schema); } public SimpleFeature feature() throws IOException { if (curr == null && count > 0) { curr = readNextFeature(); } return curr; } public SimpleFeature next() throws IOException { curr = readNextFeature(); return curr; } private SimpleFeature readNextFeature() throws IOException { if (count <= 0) { return null; } // move to the next feature offset raf.seek(offset); // read the fid, check for file end String fid = raf.readUTF(); // read the other attributes, build the feature for (AttributeDescriptor ad : schema.getAttributeDescriptors()) { Object att = readAttribute(ad); builder.add(att); } // update the offset for the next feature offset = raf.getFilePointer(); count--; // return the feature return builder.buildFeature(fid); } /** * Reads the attributes. * * @param ad * @return * @throws IOException */ Object readAttribute(AttributeDescriptor ad) throws IOException { // See the comments in {@link MergeSortDumper#writeAttribute(RandomAccessFile, // AttributeDescriptor, Object)} to get an insight on why the method is built like this boolean isNull = raf.readBoolean(); if (isNull) { return null; } else { Class<?> binding = ad.getType().getBinding(); if (binding == Boolean.class) { return raf.readBoolean(); } else if (binding == Byte.class || binding == byte.class) { return raf.readByte(); } else if (binding == Short.class || binding == short.class) { return raf.readShort(); } else if (binding == Integer.class || binding == int.class) { return raf.readInt(); } else if (binding == Long.class || binding == long.class) { return raf.readLong(); } else if (binding == Float.class || binding == float.class) { return raf.readFloat(); } else if (binding == Double.class || binding == double.class) { return raf.readDouble(); } else if (binding == String.class) { return raf.readUTF(); } else if (binding == java.sql.Date.class) { return new java.sql.Date(raf.readLong()); } else if (binding == java.sql.Time.class) { return new java.sql.Time(raf.readLong()); } else if (binding == java.sql.Timestamp.class) { return new java.sql.Timestamp(raf.readLong()); } else if (binding == java.util.Date.class) { return new java.util.Date(raf.readLong()); } else if (Geometry.class.isAssignableFrom(binding)) { WKBReader reader = new WKBReader(); int length = raf.readInt(); byte[] buffer = new byte[length]; raf.read(buffer); try { return reader.read(buffer); } catch (ParseException e) { throw new IOException("Failed to parse the geometry WKB", e); } } else { int length = raf.readInt(); byte[] buffer = new byte[length]; raf.read(buffer); ByteArrayInputStream bis = new ByteArrayInputStream(buffer); ObjectInputStream ois = new ObjectInputStream(bis); try { return ois.readObject(); } catch (ClassNotFoundException e) { throw new IOException("Could not read back object", e); } } } } }