/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2007 - 2012, Geomatys * * 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; either * version 3 of the License, or (at your option) any later version. * * 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.geotoolkit.index.tree.manager; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.Map; import org.geotoolkit.index.tree.ChannelTreeElementMapper; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; /** * Mapper to store on hard drive all inserted Tree data.<br/> * In this case stored data type is {@link NamedEnvelope}. * * @author Remi Marechal (Geomatys). * @deprecated the Tree identifier will be stored directly into each relative Lucene data. * This class will be deleted. */ @Deprecated public final class LuceneFileTreeEltMapper extends ChannelTreeElementMapper<NamedEnvelope> { /** * File name of file which store all {@link NamedEnvelope#id}. */ private final static String ID_MAP_NAME = "idMap.bin"; /** * Mutual Coordinate Reference System from all stored NamedEnvelopes. */ private final CoordinateReferenceSystem crs; /** * CRS dimension. */ private final int dim; /** * Stream to read and write all {@link NamedEnvelope#id} at the mapIndex position. */ private final RandomAccessFile idMapInOutStream; /** * Byte file position of first stored {@link NamedEnvelope#id}. */ private final int beginPosition; /** * Byte file position, just after last stored {@link NamedEnvelope#id}. */ private long idMapCurrentPosition; /** * Create a new Tree Mapper adapted to Lucene Tree use case. * * @param crs * @param mapperOutPut path where to store all Tree data. * @throws IOException if pblem during head file writing. */ public LuceneFileTreeEltMapper(final CoordinateReferenceSystem crs, final File mapperOutPut) throws IOException { super(Files.newByteChannel(mapperOutPut.toPath(), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING), 4096, ((crs.getCoordinateSystem().getDimension() << 1) * Double.SIZE + Integer.SIZE + Long.SIZE) >> 3); final File idMapOutPut = new File(mapperOutPut.getParent(), ID_MAP_NAME); idMapInOutStream = new RandomAccessFile(idMapOutPut, "rw"); // prepare to store idMapCurrentPosition during close() call. idMapInOutStream.writeLong(-1); // write crs final ByteArrayOutputStream temp = new ByteArrayOutputStream(); final ObjectOutputStream objOutput = new ObjectOutputStream(temp); objOutput.writeObject(crs); objOutput.flush(); final byte[] crsByteArray = temp.toByteArray(); idMapInOutStream.writeInt(crsByteArray.length); idMapInOutStream.write(crsByteArray); objOutput.close(); this.beginPosition = (int) idMapInOutStream.getChannel().position(); this.dim = crs.getCoordinateSystem().getDimension(); this.crs = crs; this.idMapCurrentPosition = beginPosition; } /** * Build an approriate Tree Mapper from an already filled Mapper file. * * @param mapperInput File path which contain already filled {@link File}. * @throws IOException if pblem during file head reading * @throws ClassNotFoundException if pblem during crs file head reading. */ public LuceneFileTreeEltMapper(final File mapperInput, CoordinateReferenceSystem crs) throws IOException, ClassNotFoundException { super(Files.newByteChannel(mapperInput.toPath(), StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE), 4096, ((crs.getCoordinateSystem().getDimension() << 1) * Double.SIZE + Integer.SIZE + Long.SIZE) >> 3); final File idMapOutPut = new File(mapperInput.getParent(), ID_MAP_NAME); idMapInOutStream = new RandomAccessFile(idMapOutPut, "rw"); this.idMapCurrentPosition = idMapInOutStream.readLong(); if (idMapCurrentPosition == -1) throw new IllegalStateException("You should call close method before."); // read CRS final int byteTabLength = idMapInOutStream.readInt(); final byte[] crsByteArray = new byte[byteTabLength]; idMapInOutStream.read(crsByteArray, 0, byteTabLength); final ObjectInputStream crsInputS = new ObjectInputStream(new ByteArrayInputStream(crsByteArray)); this.crs = (CoordinateReferenceSystem) crsInputS.readObject(); crsInputS.close(); this.beginPosition = (int) idMapInOutStream.getChannel().position(); this.dim = crs.getCoordinateSystem().getDimension(); } /** * {@inheritDoc }. */ @Override protected void writeObject(final NamedEnvelope Object) throws IOException { final String neID = Object.getId(); idMapInOutStream.getChannel().position(idMapCurrentPosition); byteBuffer.putLong(idMapCurrentPosition); idMapInOutStream.writeUTF(neID); idMapCurrentPosition = (int) idMapInOutStream.getChannel().position(); byteBuffer.putInt(Object.getNbEnv()); for (int d = 0; d < dim; d++) { byteBuffer.putDouble(Object.getLower(d)); byteBuffer.putDouble(Object.getUpper(d)); } } /** * {@inheritDoc } * Moreover store {@link NamedEnvelope#id} in other file, which is in the same * parent directory as TreeMapper file. */ @Override protected NamedEnvelope readObject() throws IOException { final long idPos = byteBuffer.getLong(); final FileChannel idChan = idMapInOutStream.getChannel(); idChan.position(idPos); final String neID = idMapInOutStream.readUTF(); assert (neID != null) : "stored Named Envelope should not have a null identifier. Problem during identifier reading."; final int nbEnvelope = byteBuffer.getInt(); final NamedEnvelope resultEnvelope = new NamedEnvelope(crs, neID, nbEnvelope); for (int d = 0; d < dim; d++) { final double lower = byteBuffer.getDouble(); final double upper = byteBuffer.getDouble(); resultEnvelope.setRange(d, lower, upper); } return resultEnvelope; } @Override public synchronized int getTreeIdentifier(NamedEnvelope object) throws IOException { try { return super.getTreeIdentifier(object); } catch (IllegalStateException ex) { return -1; } } /** * {@inheritDoc } */ @Override protected boolean areEquals(final NamedEnvelope objectA, final NamedEnvelope objectB) { return objectA.getId().equals(objectB.getId()); } /** * {@inheritDoc } */ @Override public Envelope getEnvelope(final NamedEnvelope object) throws IOException { return object; } /** * {@inheritDoc } */ @Override public void clear() throws IOException { super.clear(); idMapInOutStream.getChannel().position(beginPosition); idMapCurrentPosition = beginPosition; } /** * {@inheritDoc } */ @Override public void flush() throws IOException { super.flush(); final long chanPos = idMapInOutStream.getChannel().position(); final long buffPos = byteBuffer.position(); idMapInOutStream.getChannel().position(0); idMapInOutStream.writeLong(idMapCurrentPosition); idMapInOutStream.getChannel().position(chanPos); assert (chanPos + buffPos) == (idMapInOutStream.getChannel().position() + byteBuffer.position()): "LuceneTreeEltMapper.flush() expected : "+(chanPos + buffPos)+" found : "+(idMapInOutStream.getChannel().position() + byteBuffer.position()); } /** * {@inheritDoc } */ @Override public void close() throws IOException { super.close(); idMapInOutStream.getChannel().position(0); idMapInOutStream.writeLong(idMapCurrentPosition); idMapInOutStream.close(); } @Override public Map<Integer, NamedEnvelope> getFullMap() throws IOException { throw new UnsupportedOperationException("Not supported yet int File implementation."); } }