/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-2011, 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.ng; import java.awt.RenderingHints.Key; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.URI; import java.net.URL; import java.nio.charset.Charset; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.TimeZone; import java.util.logging.Logger; import org.geotools.data.AbstractDataStoreFactory; import org.geotools.data.DataStore; import org.geotools.data.DataUtilities; import org.geotools.data.directory.DirectoryDataStore; import org.geotools.data.directory.FileStoreFactory; import org.geotools.data.shapefile.ng.files.ShpFiles; import org.geotools.util.KVP; import org.geotools.util.logging.Logging; /** * Builds instances of the shapefile data store * * @source $URL$ */ public class ShapefileDataStoreFactory extends AbstractDataStoreFactory { static final Logger LOGGER = Logging.getLogger("org.geotools.data.shapefile"); /** * url to the .shp file. */ public static final Param URLP = new Param("url", URL.class, "url to a .shp file", true, null, new KVP(Param.EXT, "shp")); /** * Optional - uri of the FeatureType's namespace */ public static final Param NAMESPACEP = new Param("namespace", URI.class, "uri to a the namespace", false, null, // not required new KVP(Param.LEVEL, "advanced")); /** * Optional - enable/disable the use of memory-mapped io */ public static final Param MEMORY_MAPPED = new Param("memory mapped buffer", Boolean.class, "enable/disable the use of memory-mapped io", false, false, new KVP(Param.LEVEL, "advanced")); /** * Optional - enable/disable the use of memory-mapped io */ public static final Param CACHE_MEMORY_MAPS = new Param("cache and reuse memory maps", Boolean.class, "only memory map a file one, then cache and reuse the map", false, true, new KVP(Param.LEVEL, "advanced")); /** * Optional - discriminator for directory stores */ public static final Param FILE_TYPE = new Param("filetype", String.class, "Discriminator for directory stores", false, "shapefile", new KVP(Param.LEVEL, "advanced")); /** * Optional - Enable/disable the automatic creation of spatial index */ public static final Param CREATE_SPATIAL_INDEX = new Param("create spatial index", Boolean.class, "enable/disable the automatic creation of spatial index", false, true, new KVP(Param.LEVEL, "advanced")); /** * Optional - character used to decode strings from the DBF file */ public static final Param DBFCHARSET = new Param("charset", Charset.class, "character used to decode strings from the DBF file", false, Charset.forName("ISO-8859-1"), new KVP(Param.LEVEL, "advanced")) { /* * This is an example of a non simple Param type where a custom parse method is required. * * @see org.geotools.data.DataStoreFactorySpi.Param#parse(java.lang.String) */ public Object parse(String text) throws IOException { return Charset.forName(text); } public String text(Object value) { return ((Charset) value).name(); } }; /** * Optional - timezone to decode dates from the DBF file */ public static final Param DBFTIMEZONE = new Param("timezone", TimeZone.class, "time zone used to read dates from the DBF file", false, TimeZone.getDefault(), new KVP(Param.LEVEL, "advanced")) { public Object parse(String text) throws IOException { return TimeZone.getTimeZone(text); } public String text(Object value) { return ((TimeZone) value).getID(); } }; public String getDisplayName() { return "Shapefile"; } public String getDescription() { return "ESRI(tm) Shapefiles (*.shp)"; } public Param[] getParametersInfo() { return new Param[] { URLP, NAMESPACEP, CREATE_SPATIAL_INDEX, DBFCHARSET, DBFTIMEZONE, MEMORY_MAPPED, CACHE_MEMORY_MAPS, FILE_TYPE }; } public boolean isAvailable() { return true; } public Map<Key, ?> getImplementationHints() { return Collections.EMPTY_MAP; } public DataStore createDataStore(Map<String, Serializable> params) throws IOException { URL url = lookup(URLP, params, URL.class); Boolean isMemoryMapped = lookup(MEMORY_MAPPED, params, Boolean.class); Boolean cacheMemoryMaps = lookup(CACHE_MEMORY_MAPS, params, Boolean.class); URI namespace = lookup(NAMESPACEP, params, URI.class); Charset dbfCharset = lookup(DBFCHARSET, params, Charset.class); TimeZone dbfTimeZone = lookup(DBFTIMEZONE, params, TimeZone.class); Boolean isCreateSpatialIndex = lookup(CREATE_SPATIAL_INDEX, params, Boolean.class); // are we creating a directory of shapefiles store, or a single one? File dir = DataUtilities.urlToFile(url); if (dir != null && dir.isDirectory()) { return new DirectoryDataStore(DataUtilities.urlToFile(url), new ShpFileStoreFactory( this, params)); } else { ShpFiles shpFiles = new ShpFiles(url); boolean isLocal = shpFiles.isLocal(); boolean useMemoryMappedBuffer = isLocal && isMemoryMapped.booleanValue(); boolean createIndex = isCreateSpatialIndex.booleanValue() && isLocal; // build the store ShapefileDataStore store = new ShapefileDataStore(url); if(namespace != null) { store.setNamespaceURI(namespace.toString()); } store.setMemoryMapped(useMemoryMappedBuffer); store.setBufferCachingEnabled(cacheMemoryMaps); store.setCharset(dbfCharset); store.setTimeZone(dbfTimeZone); store.setIndexed(createIndex); return store; } } public DataStore createNewDataStore(Map<String, Serializable> params) throws IOException { return createDataStore(params); } /** * Looks up a parameter, if not found it returns the default value, assuming there is one, or * null otherwise * * @param <T> * @param param * @param params * @param target * @return * @throws IOException */ <T> T lookup(Param param, Map<String, Serializable> params, Class<T> target) throws IOException { T result = (T) param.lookUp(params); if (result == null) { return (T) param.getDefaultValue(); } else { return result; } } @Override public boolean canProcess(Map params) { if (!super.canProcess(params)) { return false; } try { URL url = (URL) URLP.lookUp(params); if (canProcess(url)) { return true; } else { // maybe it's a directory? Object fileType = FILE_TYPE.lookUp(params); File dir = DataUtilities.urlToFile(url); // check for null fileType for backwards compatibility return dir.isDirectory() && (fileType == null || "shapefile".equals(fileType)); } } catch (IOException e) { return false; } } public boolean canProcess(URL f) { return f != null && f.getFile().toUpperCase().endsWith("SHP"); } /** * A delegates that allow to build a directory of shapfiles store * * @author Andrea Aime - OpenGeo */ public static class ShpFileStoreFactory implements FileStoreFactory { ShapefileDataStoreFactory shpFactory; Map originalParams; public ShpFileStoreFactory(ShapefileDataStoreFactory factory, Map originalParams) { this.shpFactory = factory; this.originalParams = originalParams; } public DataStore getDataStore(File file) throws IOException { final URL url = DataUtilities.fileToURL(file); if (shpFactory.canProcess(url)) { Map params = new HashMap(originalParams); params.put(URLP.key, url); return shpFactory.createDataStore(params); } else { return null; } } } }