001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: * (C) 2005, Institut de Recherche pour le Développement
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation;
010: * version 2.1 of the License.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: */
017: package org.geotools.referencing.factory.epsg;
018:
019: // J2SE dependencies
020: import java.util.Properties;
021: import java.util.logging.LogRecord;
022: import java.sql.Connection;
023: import java.sql.DriverManager;
024: import java.sql.SQLException;
025: import java.io.File;
026: import java.io.PrintWriter;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.FileInputStream;
030: import java.lang.reflect.Constructor;
031:
032: // Geotools dependencies
033: import org.geotools.factory.Hints;
034: import org.geotools.referencing.factory.ReferencingFactory;
035: import org.geotools.referencing.factory.AbstractAuthorityFactory;
036: import org.geotools.resources.i18n.ErrorKeys;
037: import org.geotools.resources.i18n.Errors;
038: import org.geotools.resources.JDBC;
039:
040: /**
041: * Open a connection to an EPSG database using {@link DriverManager}. This implementation is not
042: * suitable for uses with Java Naming and Directory (JNDI), but it provides a convenient base class
043: * for connections determined from properties files.
044: * <p>
045: * The default implementation doesn't make any assumption about where the properties file is
046: * located. The properties file location must be supplied at construction time. Because this
047: * base class dosn't have a no-argument constructor, it can't be registered in the
048: * {@code META-INF/services/} directory. If such a registration is wanted (for automatic detection
049: * by {@link org.geotools.referencing.ReferencingFactoryFinder}, then users must provide a subclass with a
050: * no-argument constructor.
051: * <p>
052: * The properties file to be supplied at construction time shall contains the following:
053: * <p>
054: *
055: * <TABLE BORDER="1">
056: * <TR>
057: * <TH>Property</TH>
058: * <TH>Description</TH>
059: * <TH>Default</TH>
060: * </TR>
061: * <TR>
062: * <TD>{@code url}</TD>
063: * <TD>The URL to the EPSG database</TD>
064: * <TD>{@code jdbc:odbc:EPSG}</TD>
065: * </TR>
066: * <TR>
067: * <TD>{@code schema}</TD>
068: * <TD>The schema containing EPSG tables in the database</TD>
069: * <TD></TD>
070: * </TR>
071: * <TR>
072: * <TD>{@code user}</TD>
073: * <TD>User used to make database connections</TD>
074: * <TD></TD>
075: * </TR>
076: * <TR>
077: * <TD>{@code password}</TD>
078: * <TD>Password used to make database connections</TD>
079: * <TD></TD>
080: * </TR>
081: * <TR>
082: * <TD>{@code driver}</TD>
083: * <TD>The JDBC driver to load</TD>
084: * <TD>{@code sun.jdbc.odbc.JdbcOdbcDriver}</Td>
085: * </TR>
086: * <TR>
087: * <TD>{@code factory}</TD>
088: * <TD>The EPSG factory to instantiate</TD>
089: * <TD>{@code org.geotools.referencing.factory.epsg.DirectEpsgFactory}</TD>
090: * </TR>
091: * </TABLE>
092: *
093: * @since 2.2
094: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/SimpleDataSource.java $
095: * @version $Id: SimpleDataSource.java 26096 2007-06-29 21:45:12Z jgarnett $
096: * @author Martin Desruisseaux
097: *
098: * @deprecated Experience suggests that subclassing {@code javax.sql.DataSource} is a cause of
099: * troubles in JEE environments. Subclass directly {@link ThreadedEpsgFactory} instead.
100: */
101: public class SimpleDataSource implements DataSource {
102: /**
103: * The properties used for etablishing the database connection. See the
104: * {@linkplain SimpleDataSource class description} for the expected content.
105: * This field is never {@code null}.
106: */
107: protected final Properties properties;
108:
109: /**
110: * Constructs a data source with the specified properties.
111: * The properties given to this constructor are not cloned.
112: *
113: * @param properties The properties, or {@code null} for an empty set.
114: */
115: public SimpleDataSource(final Properties properties) {
116: this .properties = (properties != null) ? properties
117: : new Properties();
118: }
119:
120: /**
121: * Constructs a data source with properties loaded from the specified file.
122: *
123: * @param file The properties file to load.
124: * @throws IOException if an error occured while loading the properties file.
125: */
126: public SimpleDataSource(final File file) throws IOException {
127: properties = new Properties();
128: final InputStream in = new FileInputStream(file);
129: properties.load(in);
130: in.close();
131: }
132:
133: /**
134: * Retrieves the log writer. The default implementation delegates to the {@link DriverManager},
135: * which returns a system-wide logger.
136: */
137: public PrintWriter getLogWriter() throws SQLException {
138: return DriverManager.getLogWriter();
139: }
140:
141: /**
142: * Sets the log writer. The default implementation delegates to the {@link DriverManager},
143: * which have a system-wide effect.
144: */
145: public void setLogWriter(final PrintWriter out) throws SQLException {
146: DriverManager.setLogWriter(out);
147: }
148:
149: /**
150: * Gets the maximum time in seconds that this data source can wait while attempting to
151: * connect to a database. The default implementation returns zero, which means that the
152: * timeout is the default system timeout .
153: */
154: public int getLoginTimeout() throws SQLException {
155: return 0;
156: }
157:
158: /**
159: * Sets the maximum time in seconds that this data source will wait while attempting to
160: * connect to a database. The default implementation does nothing.
161: */
162: public void setLoginTimeout(final int seconds) throws SQLException {
163: }
164:
165: /**
166: * Returns the priority for this data source. The default implementation returns
167: * {@link #NORMAL_PRIORITY NORMAL_PRIORITY}.
168: */
169: public int getPriority() {
170: return NORMAL_PRIORITY;
171: }
172:
173: /**
174: * Returns the URL to the database.
175: *
176: * @todo Remove the call to loadDriver when we will be allowed to compile for J2SE 1.6.
177: */
178: private String getURL() {
179: final LogRecord log;
180: log = JDBC.loadDriver(properties.getProperty("driver",
181: "sun.jdbc.odbc.JdbcOdbcDriver"));
182: if (log != null) {
183: log.setSourceClassName(SimpleDataSource.class.getName());
184: log.setSourceMethodName("getConnection");
185: ReferencingFactory.LOGGER.log(log);
186: }
187: return properties.getProperty("url", "jdbc:odbc:EPSG");
188: }
189:
190: /**
191: * Attempts to establish a connection with the data source.
192: *
193: * @return A connection to the data source.
194: * @exception SQLException if a database access error occurs.
195: */
196: public Connection getConnection() throws SQLException {
197: return DriverManager.getConnection(getURL(), properties);
198: }
199:
200: /**
201: * Attempts to establish a connection with the data source.
202: *
203: * @param username The database user on whose behalf the connection is being made.
204: * @param password The user's password.
205: * @return A connection to the data source.
206: * @exception SQLException if a database access error occurs.
207: */
208: public Connection getConnection(final String username,
209: final String password) throws SQLException {
210: return DriverManager
211: .getConnection(getURL(), username, password);
212: }
213:
214: /**
215: * Opens a connection and creates an EPSG factory for it. The default implementation attempts
216: * to create an instance of the class specified by the {@code "factory"} key. This class shall
217: * have a constructor expecting the following arguments in that order: {@link Hints},
218: * {@link Connection}.
219: */
220: public AbstractAuthorityFactory createFactory(final Hints hints)
221: throws SQLException {
222: final Connection connection = getConnection();
223: String classname = properties.getProperty("factory");
224: if (classname == null) {
225: classname = "org.geotools.referencing.factory.epsg.DirectEpsgFactory";
226: final String driver = properties.getProperty("driver");
227: if (driver != null) {
228: // TODO: 'contains' instead of 'indexOf' when we will be allowed to target J2SE 1.5.
229: if (driver.indexOf(".postgresql.") >= 0
230: || driver.indexOf(".mysql.") >= 0) {
231: classname = "org.geotools.referencing.factory.epsg.AnsiDialectEpsgFactory";
232: } else if (driver.startsWith("oracle.")) {
233: classname = "org.geotools.referencing.factory.epsg.OracleDialectEpsgFactory";
234: } else if (driver.indexOf(".hsqldb.") >= 0) {
235: classname = "org.geotools.referencing.factory.epsg.FactoryUsingHSQL";
236: }
237: }
238: }
239: final AbstractAuthorityFactory factory;
240: try {
241: final Class classe = Class.forName(classname);
242: final Constructor c = classe.getConstructor(new Class[] {
243: Hints.class, Connection.class });
244: factory = (AbstractAuthorityFactory) c
245: .newInstance(new Object[] { hints, connection });
246: } catch (Exception exception) {
247: final SQLException e;
248: e = new SQLException(Errors.format(
249: ErrorKeys.CANT_CONNECT_DATABASE_$1, getURL()));
250: e.initCause(exception);
251: throw e;
252: }
253: final String schema = properties.getProperty("schema");
254: if (schema != null) {
255: if (factory instanceof FactoryUsingAnsiSQL) {
256: ((FactoryUsingAnsiSQL) factory).setSchema(schema);
257: }
258: }
259: return factory;
260: }
261:
262: /**
263: * Not implemented. This method is defined for Java 6 compatibility only.
264: *
265: * @since 2.4
266: */
267: public Object unwrap(final Class type) throws SQLException {
268: throw new SQLException();
269: }
270:
271: /**
272: * Not implemented. This method is defined for Java 6 compatibility only.
273: *
274: * @since 2.4
275: */
276: public boolean isWrapperFor(final Class type) throws SQLException {
277: return false;
278: }
279: }
|