001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.data.shapefile.indexed;
017:
018: import java.io.File;
019: import java.io.FileInputStream;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.RandomAccessFile;
023: import java.net.URL;
024: import java.nio.channels.Channels;
025: import java.nio.channels.FileChannel;
026: import java.nio.channels.ReadableByteChannel;
027: import java.util.logging.Logger;
028:
029: import org.geotools.data.DataUtilities;
030: import org.geotools.data.shapefile.ShapefileDataStore;
031: import org.geotools.data.shapefile.shp.IndexFile;
032:
033: /**
034: * Creates a .fix file (fid index).
035: *
036: * @author Jesse
037: */
038: public class FidIndexer {
039: static Logger LOGGER = org.geotools.util.logging.Logging
040: .getLogger("org.geotools.data.shapefile");
041:
042: public static synchronized URL generate(URL shpURL)
043: throws IOException {
044: LOGGER.fine("Generating fids for " + shpURL);
045: IndexedFidWriter writer = null;
046: IndexFile indexFile = null;
047:
048: try {
049: String filename;
050:
051: try {
052: filename = java.net.URLDecoder.decode(
053: shpURL.toString(), "US-ASCII");
054: filename = filename.substring(0, filename
055: .lastIndexOf(".shp"));
056: } catch (java.io.UnsupportedEncodingException use) {
057: throw new java.net.MalformedURLException(
058: "Unable to decode " + shpURL + " cause "
059: + use.getMessage());
060: }
061:
062: int indexslash = filename.lastIndexOf(File.pathSeparator);
063:
064: if (indexslash == -1) {
065: indexslash = 0;
066: }
067:
068: URL fixURL = new URL(filename + ".fix");
069: URL indexURL = new URL(filename + ".shx");
070:
071: if (DataUtilities.urlToFile(fixURL).exists())
072: return fixURL;
073:
074: if (!(DataUtilities.urlToFile(indexURL).exists()))
075: return null;
076:
077: indexFile = new IndexFile(getReadChannel(indexURL));
078: FileChannel writeChannel = getWriteChannel(fixURL);
079:
080: writer = new IndexedFidWriter(writeChannel,
081: new IndexedFidReader(
082: filename.substring(indexslash),
083: writeChannel));
084:
085: for (int i = 0, j = indexFile.getRecordCount(); i < j; i++) {
086: writer.next();
087: }
088:
089: return fixURL;
090: } finally {
091: try {
092: if (indexFile != null) {
093: indexFile.close();
094: }
095: } finally {
096:
097: if (writer != null) {
098: writer.close();
099: }
100: }
101: }
102: }
103:
104: /**
105: * Obtain a ReadableByteChannel from the given URL. If the url
106: * protocol is file, a FileChannel will be returned. Otherwise a generic
107: * channel will be obtained from the urls input stream.
108: *
109: * @param url DOCUMENT ME!
110: *
111: * @return DOCUMENT ME!
112: *
113: * @throws IOException DOCUMENT ME!
114: */
115: protected static ReadableByteChannel getReadChannel(URL url)
116: throws IOException {
117: ReadableByteChannel channel = null;
118:
119: if (url.getProtocol().equals("file")) { // && useMemoryMappedBuffer) {
120:
121: File file = DataUtilities.urlToFile(url);
122:
123: if (!file.exists()) {
124: throw new IOException("File doesn't exist: " + file);
125: }
126:
127: if (!file.canRead()) {
128: throw new IOException("File isn't readable: " + file);
129: }
130:
131: FileInputStream in = new FileInputStream(file);
132: channel = in.getChannel();
133: } else {
134: InputStream in = url.openConnection().getInputStream();
135: channel = Channels.newChannel(in);
136: }
137:
138: return channel;
139: }
140:
141: /**
142: * Obtain a WritableByteChannel from the given URL. If the url
143: * protocol is file, a FileChannel will be returned. Currently, this
144: * method will return a generic channel for remote urls, however both
145: * shape and dbf writing can only occur with a local FileChannel channel.
146: *
147: * @param url DOCUMENT ME!
148: *
149: * @return DOCUMENT ME!
150: *
151: * @throws IOException DOCUMENT ME!
152: */
153: protected static FileChannel getWriteChannel(URL url)
154: throws IOException {
155: FileChannel channel;
156:
157: if (url.getProtocol().equals("file")) { // && useMemoryMappedBuffer) {
158:
159: File file = DataUtilities.urlToFile(url);
160:
161: RandomAccessFile raf = new RandomAccessFile(file, "rw");
162: channel = raf.getChannel();
163:
164: ((FileChannel) channel).lock();
165:
166: return channel;
167: } else {
168: return null;
169: }
170: }
171: }
|