📄 filesystemnode.java
字号:
/*
* GeoTools - OpenSource mapping toolkit
* http://geotools.org
* (C) 2003-2006, GeoTools Project Managment Committee (PMC)
* (C) 2002, Centre for Computational Geography
*
* 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.index.rtree.cachefs;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.util.EmptyStackException;
import org.geotools.index.Data;
import org.geotools.index.DataDefinition;
import org.geotools.index.TreeException;
import org.geotools.index.DataDefinition.Field;
import org.geotools.index.rtree.Entry;
import org.geotools.index.rtree.Node;
import com.vividsolutions.jts.geom.Envelope;
/**
* DOCUMENT ME!
*
* @author Tommaso Nolli
* @source $URL:
* http://svn.geotools.org/geotools/trunk/gt/modules/plugin/shapefile/src/main/java/org/geotools/index/rtree/cachefs/FileSystemNode.java $
*/
public class FileSystemNode extends Node {
static final int ENTRY_SIZE = 40;
private static int pageLen = 0;
private Parameters params = null;
private boolean flushNeeded;
private long parentOffset = -1;
private long offset = -1;
private FileSystemNode(Parameters params, boolean getFromFree) {
super(params.getMaxNodeEntries());
this.params = params;
if (pageLen == 0) {
pageLen = (params.getMaxNodeEntries() * ENTRY_SIZE) + 9; // Flag
// (leaf
// or
// not)
}
Long oOffset = null;
if (getFromFree) {
try {
oOffset = (Long) this.params.getFreePages().pop();
} catch (EmptyStackException e) {
// The stack is empty
}
}
this.offset = (oOffset == null) ? (-1) : oOffset.longValue();
this.flushNeeded = false;
}
/**
* DOCUMENT ME!
*
* @param params
*/
public FileSystemNode(Parameters params) {
this(params, true);
}
/**
* DOCUMENT ME!
*
* @param params
* @param offset
* DOCUMENT ME!
*
* @throws IOException
* DOCUMENT ME!
* @throws TreeException
* DOCUMENT ME!
*/
public FileSystemNode(Parameters params, long offset) throws IOException,
TreeException {
this(params, false);
this.offset = offset;
FileChannel channel = this.params.getChannel();
ByteBuffer buf = this.getEmptyByteBuffer();
ByteBuffer dataBuf = null;
synchronized (channel) {
channel.position(offset);
channel.read(buf);
// Check if I'm a leaf
buf.position(0);
this.setLeaf(buf.get() == (byte) 1);
// If I'm a leaf, read the data
if (this.isLeaf()) {
dataBuf = this.getEmptyByteBuffer(this.params.getDataDef());
channel.read(dataBuf);
dataBuf.position(0);
}
}
this.parentOffset = buf.getLong();
double x1;
double x2;
double y1;
double y2;
long p;
Entry entry = null;
for (int i = 0; i < this.params.getMaxNodeEntries(); i++) {
x1 = buf.getDouble();
x2 = buf.getDouble();
y1 = buf.getDouble();
y2 = buf.getDouble();
p = buf.getLong();
if ((x1 == 0) && (x2 == 0) && (y1 == 0) && (y2 == 0) && (p == 0)) {
// This is an empty entry
break;
}
if (this.isLeaf()) {
entry = new Entry(new Envelope(x1, x2, y1, y2), this.loadData(
dataBuf, this.params.getDataDef()));
} else {
entry = new Entry(new Envelope(x1, x2, y1, y2), new Long(p));
}
this.addEntry(entry);
}
}
/**
* DOCUMENT ME!
*
* @param buf
* @param def
*
*
* @throws TreeException
*/
private Data loadData(ByteBuffer buf, DataDefinition def)
throws TreeException {
Data data = new Data(def);
Field field = null;
for (int i = 0; i < def.getFieldsCount(); i++) {
field = def.getField(i);
if (field.getFieldClass().equals(Short.class)) {
data.addValue(new Short(buf.getShort()));
} else if (field.getFieldClass().equals(Integer.class)) {
data.addValue(new Integer(buf.getInt()));
} else if (field.getFieldClass().equals(Long.class)) {
data.addValue(new Long(buf.getLong()));
} else if (field.getFieldClass().equals(Float.class)) {
data.addValue(new Float(buf.getFloat()));
} else if (field.getFieldClass().equals(Double.class)) {
data.addValue(new Double(buf.getDouble()));
} else if (field.getFieldClass().equals(String.class)) {
byte[] bytes = new byte[field.getEncodedLen()];
buf.get(bytes);
CharBuffer cb = def.getCharset().decode(ByteBuffer.wrap(bytes));
cb.position(0);
data.addValue(cb.toString().trim());
}
}
return data;
}
/**
* DOCUMENT ME!
*
*/
private ByteBuffer getEmptyByteBuffer() {
return ByteBuffer.allocate(pageLen);
}
/**
* DOCUMENT ME!
*
* @param dataDef
*
*/
private ByteBuffer getEmptyByteBuffer(DataDefinition dataDef) {
int bufLen = dataDef.getEncodedLen() * this.params.getMaxNodeEntries();
return ByteBuffer.allocate(bufLen);
}
/**
* DOCUMENT ME!
*
*/
long getOffset() {
return this.offset;
}
/**
* @see org.geotools.rtree.Node#getParent()
*/
public Node getParent() throws TreeException {
FileSystemNode node = null;
try {
node = this.params.getFromCache(this.parentOffset);
} catch (IOException e) {
throw new TreeException(e);
}
return node;
}
/**
* Flushes this node to disk
*
* <pre>
* Node page structure:
* 1 * byte --> 1 = leaf, 2 = non leaf
* 1 * long --> parent offset
* entries len * 40 --> the entries
*
* each entry is as follow
* 4 * double --> the bounding box (x1, x2, y1, y2)
* 1 * long --> the pointer (-1 if leaf)
*
* Data pages are immediatly after leaf Node pages.
*
* </pre>
*
* @throws TreeException
* DOCUMENT ME!
*/
public void flush() throws TreeException {
if (!this.flushNeeded) {
return;
}
FileChannel channel = this.params.getChannel();
try {
// Prepare buffers...
ByteBuffer buf = this.getEmptyByteBuffer();
ByteBuffer dataBuf = null;
if (this.isLeaf()) {
dataBuf = this.getEmptyByteBuffer(this.params.getDataDef());
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -