/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-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.referencing.factory.epsg; // J2SE dependencies import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; import java.util.Properties; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; import javax.sql.DataSource; // Geotools dependencies import org.geotools.util.logging.Logging; import org.geotools.factory.Hints; import org.geotools.referencing.factory.AbstractAuthorityFactory; // PostgreSQL dependencies import org.postgresql.ds.common.BaseDataSource; import org.postgresql.jdbc3.Jdbc3SimpleDataSource; /** * Connection to the EPSG database in PostgreSQL database engine using JDBC. The EPSG * database can be downloaded from <A HREF="http://www.epsg.org">http://www.epsg.org</A>. * It should have been imported into a PostgreSQL database, which doesn't need to be on * the local machine. * <p> * <h3>Connection parameters</h3> * The preferred way to specify connection parameters is through the JNDI interface. * However, this datasource provides the following alternative as a convenience: if a * {@value #CONFIGURATION_FILE} file is found in current directory or in the user's home * directory, then the following properties are fetch. Note that the default value may change * in a future version if a public server become available. * <P> * <TABLE BORDER="1"> * <TR> * <TH>Property</TH> * <TH>Type</TH> * <TH>Description</TH> * <TH>Geotools Default</TH> * </TR> * <TR> * <TD>{@code serverName}</TD> * <TD>String</TD> * <TD>PostgreSQL database server host name</TD> * <TD>{@code localhost}</TD> * </TR> * <TR> * <TD>{@code databaseName}</TD> * <TD>String</TD> * <TD>PostgreSQL database name</TD> * <TD>{@code EPSG}</TD> * </TR> * <TR> * <TD>{@code schema}</TD> * <TD>String</TD> * <TD>The schema for the EPSG tables</TD> * <TD></TD> * </TR> * <TR> * <TD>{@code portNumber}</TD> * <TD>int</TD> * <TD>TCP port which the PostgreSQL database server is listening on</TD> * <TD>{@code 5432}</TD> * </TR> * <TR> * <TD>{@code user}</TD> * <TD>String</TD> * <TD>User used to make database connections</TD> * <TD>{@code GeoTools}</TD> * </TR> * <TR> * <TD>{@code password}</TD> * <TD>String</TD> * <TD>Password used to make database connections</TD> * <TD>{@code GeoTools}</TD></TR> * </TABLE> * <P> * The database version is given in the * {@linkplain org.opengis.metadata.citation.Citation#getEdition edition attribute} * of the {@linkplain org.opengis.referencing.AuthorityFactory#getAuthority authority}. * The postgreSQL database should be read only. * <P> * Just having this class accessible in the classpath, together with the registration in * the {@code META-INF/services/} directory, is suffisient to get a working EPSG authority * factory backed by this database. Vendors can create a copy of this class, modify it and * bundle it with their own distribution if they want to connect their users to an other * database. * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Didier Richard * @author Martin Desruisseaux * * @tutorial http://docs.codehaus.org/display/GEOTOOLS/How+to+install+the+EPSG+database+in+PostgreSQL */ public class ThreadedPostgreSQLEpsgFactory extends ThreadedEpsgFactory { /** * The user configuration file. This class search first for the first file found in the * following directories: * <ul> * <li>The current directory</li> * <li>The user's home directory</li> * </ul> */ public static final String CONFIGURATION_FILE = "EPSG-DataSource.properties"; /** * The schema name, or {@code null} if none. */ private String schema; /** * Creates a new instance of this factory. */ public ThreadedPostgreSQLEpsgFactory() { this(null); } /** * Creates a new instance of this factory with the specified hints. * The priority is set to a lower value than the {@linkplain FactoryOnAccess}'s one * in order to give the priority to any "official" database installed locally by the * user, when available. */ public ThreadedPostgreSQLEpsgFactory(final Hints hints) { super(hints, PRIORITY + 5); } /** * Loads the {@linkplain #CONFIGURATION_FILE configuration file}. */ private static Properties load() { final Properties p = new Properties(); File file = new File(CONFIGURATION_FILE); if (!file.isFile()) { file = new File(System.getProperty("user.home", "."), CONFIGURATION_FILE); if (!file.isFile()) { // Returns an empty set of properties. return p; } } try { final InputStream in = new FileInputStream(file); p.load(in); in.close(); } catch (IOException exception) { Logging.unexpectedException("org.geotools.referencing.factory", DataSource.class, "<init>", exception); // Continue. We will try to work with whatever properties are available. } return p; } /** * Returns a data source for the PostgreSQL database. */ protected DataSource createDataSource() throws SQLException { DataSource candidate = super.createDataSource(); if (candidate instanceof BaseDataSource) { // Any kind of DataSource from the PostgreSQL driver. return candidate; } final Jdbc3SimpleDataSource source = new Jdbc3SimpleDataSource(); final Properties p = load(); int portNumber; try { portNumber = Integer.parseInt(p.getProperty("portNumber", "5432")); } catch (NumberFormatException exception) { portNumber = 5432; Logging.unexpectedException("org.geotools.referencing.factory", DataSource.class, "<init>", exception); } source.setPortNumber (portNumber); source.setServerName (p.getProperty("serverName", "localhost")); source.setDatabaseName(p.getProperty("databaseName", "EPSG" )); source.setUser (p.getProperty("user", "Geotools" )); source.setPassword (p.getProperty("password", "Geotools" )); schema = p.getProperty("schema", null); return source; } /** * Returns the backing-store factory for PostgreSQL syntax. * * @param hints A map of hints, including the low-level factories to use for CRS creation. * @return The EPSG factory using PostgreSQL syntax. * @throws SQLException if connection to the database failed. */ protected AbstractAuthorityFactory createBackingStore(final Hints hints) throws SQLException { final FactoryUsingAnsiSQL factory = new FactoryUsingAnsiSQL(hints, getDataSource()); factory.setValidationQuery("select now()"); if (schema != null) { factory.setSchema(schema); } return factory; } }