Package org.geotools.data.shapefile.index.quadtree.fs

Source Code of org.geotools.data.shapefile.index.quadtree.fs.FileSystemIndexStore

/*
*    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.shapefile.index.quadtree.fs;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geotools.data.shapefile.index.quadtree.IndexStore;
import org.geotools.data.shapefile.index.quadtree.Node;
import org.geotools.data.shapefile.index.quadtree.QuadTree;
import org.geotools.data.shapefile.index.quadtree.StoreException;
import org.geotools.data.shapefile.shp.IndexFile;

import com.vividsolutions.jts.geom.Envelope;

/**
* DOCUMENT ME!
*
* @author Tommaso Nolli
*
*
* @source $URL$
*/
public class FileSystemIndexStore implements IndexStore {
    private static final Logger LOGGER = org.geotools.util.logging.Logging
            .getLogger("org.geotools.index.quadtree");
    private File file;
    private byte byteOrder;

    /**
     * Constructor. The byte order defaults to NEW_MSB_ORDER
     *
     * @param file
     */
    public FileSystemIndexStore(File file) {
        this.file = file;
        this.byteOrder = IndexHeader.NEW_MSB_ORDER;
    }

    /**
     * Constructor
     *
     * @param file
     * @param byteOrder
     */
    public FileSystemIndexStore(File file, byte byteOrder) {
        this.file = file;
        this.byteOrder = byteOrder;
    }

    /**
     * @see org.geotools.index.quadtree.IndexStore#store(org.geotools.index.quadtree.QuadTree)
     */
    public void store(QuadTree tree) throws StoreException {
        // For efficiency, trim the tree
        tree.trim();

        // Open the stream...
        FileOutputStream fos = null;
        FileChannel channel = null;

        try {
            fos = new FileOutputStream(file);
            channel = fos.getChannel();

            ByteBuffer buf = ByteBuffer.allocate(8);

            if (this.byteOrder > IndexHeader.NATIVE_ORDER) {
                LOGGER.finest("Writing file header");

                IndexHeader header = new IndexHeader(byteOrder);
                header.writeTo(buf);
                buf.flip();
                channel.write(buf);
            }

            ByteOrder order = byteToOrder(this.byteOrder);

            buf.clear();
            buf.order(order);

            buf.putInt(tree.getNumShapes());
            buf.putInt(tree.getMaxDepth());
            buf.flip();

            channel.write(buf);

            this.writeNode(tree.getRoot(), channel, order);
        } catch (IOException e) {
            throw new StoreException(e);
        } finally {
            try {
                channel.close();
            } catch (Exception e) {
            }

            try {
                fos.close();
            } catch (Exception e) {
            }
        }
    }

    /**
     * Wites a tree node to the qix file
     *
     * @param node
     *                The node
     * @param channel
     *                DOCUMENT ME!
     * @param order
     *                byte order
     *
     * @throws IOException
     * @throws StoreException
     *                 DOCUMENT ME!
     */
    private void writeNode(Node node, FileChannel channel, ByteOrder order)
            throws IOException, StoreException {
        int offset = this.getSubNodeOffset(node);

        ByteBuffer buf = ByteBuffer.allocate((4 * 8) + (3 * 4)
                + (node.getNumShapeIds() * 4));

        buf.order(order);
        buf.putInt(offset);

        Envelope env = node.getBounds();
        buf.putDouble(env.getMinX());
        buf.putDouble(env.getMinY());
        buf.putDouble(env.getMaxX());
        buf.putDouble(env.getMaxY());

        buf.putInt(node.getNumShapeIds());

        for (int i = 0; i < node.getNumShapeIds(); i++) {
            buf.putInt(node.getShapeId(i));
        }

        buf.putInt(node.getNumSubNodes());
        buf.flip();

        channel.write(buf);

        for (int i = 0; i < node.getNumSubNodes(); i++) {
            this.writeNode(node.getSubNode(i), channel, order);
        }
    }

    /**
     * Calculates the offset
     *
     * @param node
     *
     *
     * @throws StoreException
     *                 DOCUMENT ME!
     */
    private int getSubNodeOffset(Node node) throws StoreException {
        int offset = 0;
        Node tmp = null;

        for (int i = 0; i < node.getNumSubNodes(); i++) {
            tmp = node.getSubNode(i);
            offset += (4 * 8); // Envelope size
            offset += ((tmp.getNumShapeIds() + 3) * 4); // Entries size + 3
            offset += this.getSubNodeOffset(tmp);
        }

        return offset;
    }

    /**
     * Loads a quadrtee stored in a '.qix' file. <b>WARNING:</b> The resulting
     * quadtree will be immutable; if you perform an insert, an
     * <code>UnsupportedOperationException</code> will be thrown.
     *
     * @see org.geotools.index.quadtree.IndexStore#load()
     */
    public QuadTree load(IndexFile indexfile, boolean useMemoryMapping) throws StoreException {
        QuadTree tree = null;

        try {
            if (LOGGER.isLoggable(Level.FINEST)) {
                LOGGER.finest("Opening QuadTree "
                        + this.file.getCanonicalPath());
            }

            final FileInputStream fis = new FileInputStream(file);
            final FileChannel channel = fis.getChannel();

            IndexHeader header = new IndexHeader(channel);

            ByteOrder order = byteToOrder(header.getByteOrder());
            ByteBuffer buf = ByteBuffer.allocate(8);
            buf.order(order);
            channel.read(buf);
            buf.flip();

            tree = new QuadTree(buf.getInt(), buf.getInt(), indexfile) {
                public void insert(int recno, Envelope bounds) {
                    throw new UnsupportedOperationException(
                            "File quadtrees are immutable");
                }

                public boolean trim() {
                    return false;
                }

                public void close() throws StoreException {
                    super.close();
                    try {
                        channel.close();
                        fis.close();
                    } catch (IOException e) {
                        throw new StoreException(e);
                    }
                }
            };

            tree.setRoot(FileSystemNode.readNode(0, null, channel, order, useMemoryMapping));

            LOGGER.finest("QuadTree opened");
        } catch (IOException e) {
            throw new StoreException(e);
        }

        return tree;
    }

    /**
     * DOCUMENT ME!
     *
     * @param order
     *
     */
    private static ByteOrder byteToOrder(byte order) {
        ByteOrder ret = null;

        switch (order) {
        case IndexHeader.NATIVE_ORDER:
            ret = ByteOrder.nativeOrder();

            break;

        case IndexHeader.LSB_ORDER:
        case IndexHeader.NEW_LSB_ORDER:
            ret = ByteOrder.LITTLE_ENDIAN;

            break;

        case IndexHeader.MSB_ORDER:
        case IndexHeader.NEW_MSB_ORDER:
            ret = ByteOrder.BIG_ENDIAN;

            break;
        }

        return ret;
    }

    /**
     * DOCUMENT ME!
     *
     * @return Returns the byteOrder.
     */
    public int getByteOrder() {
        return this.byteOrder;
    }

    /**
     * DOCUMENT ME!
     *
     * @param byteOrder
     *                The byteOrder to set.
     */
    public void setByteOrder(byte byteOrder) {
        this.byteOrder = byteOrder;
    }
}
TOP

Related Classes of org.geotools.data.shapefile.index.quadtree.fs.FileSystemIndexStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.