root / trunk / libraries / geotools-2.1.1-epsg-hsql / src / org / geotools / referencing / factory / epsg / HSQLDataSource.java @ 28854
History | View | Annotate | Download (9.68 KB)
1 |
/*
|
---|---|
2 |
* Geotools 2 - OpenSource mapping toolkit
|
3 |
* (C) 2005, Geotools Project Managment Committee (PMC)
|
4 |
*
|
5 |
* This library is free software; you can redistribute it and/or
|
6 |
* modify it under the terms of the GNU Lesser General Public
|
7 |
* License as published by the Free Software Foundation; either
|
8 |
* version 2.1 of the License, or (at your option) any later version.
|
9 |
*
|
10 |
* This library is distributed in the hope that it will be useful,
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13 |
* Lesser General Public License for more details.
|
14 |
*
|
15 |
* You should have received a copy of the GNU Lesser General Public
|
16 |
* License along with this library; if not, write to the Free Software
|
17 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
18 |
*/
|
19 |
package org.geotools.referencing.factory.epsg; |
20 |
|
21 |
// J2SE dependencies
|
22 |
import java.io.File; |
23 |
import java.io.IOException; |
24 |
import java.io.BufferedReader; |
25 |
import java.io.InputStreamReader; |
26 |
import java.sql.ResultSet; |
27 |
import java.sql.Statement; |
28 |
import java.sql.Connection; |
29 |
import java.sql.SQLException; |
30 |
import java.util.logging.Logger; |
31 |
|
32 |
// Geotools dependencies
|
33 |
import org.geotools.factory.Hints; |
34 |
import org.geotools.referencing.factory.FactoryGroup; |
35 |
import org.geotools.referencing.factory.AbstractAuthorityFactory; |
36 |
|
37 |
// HSQL dependencies
|
38 |
import org.hsqldb.jdbc.jdbcDataSource; |
39 |
|
40 |
|
41 |
/**
|
42 |
* Connection to the EPSG database in HSQL database engine format using JDBC. The EPSG
|
43 |
* database can be downloaded from <A HREF="http://www.epsg.org">http://www.epsg.org</A>.
|
44 |
* The SQL scripts (modified for the HSQL syntax as <A HREF="doc-files/HSQL.html">explained
|
45 |
* here</A>) are bundled into this plugin. The database version is given in the
|
46 |
* {@linkplain org.opengis.metadata.citation.Citation#getEdition edition attribute}
|
47 |
* of the {@linkplain org.opengis.referencing.AuthorityFactory#getAuthority authority}.
|
48 |
* The HSQL database is read only.
|
49 |
* <P>
|
50 |
* <H3>Implementation note</H3>
|
51 |
* The SQL scripts are executed the first time a connection is required. The database
|
52 |
* is then created as cached tables ({@code HSQL.properties} and {@code HSQL.data} files)
|
53 |
* in a temporary directory. Future connections to the EPSG database while reuse the cached
|
54 |
* tables, if available. Otherwise, the scripts will be executed again in order to recreate
|
55 |
* them.
|
56 |
*
|
57 |
* @version $Id: HSQLDataSource.java 14624 2005-06-29 02:19:08Z desruisseaux $
|
58 |
* @author Martin Desruisseaux
|
59 |
* @author Didier Richard
|
60 |
*
|
61 |
* @since 2.2
|
62 |
*/
|
63 |
public class HSQLDataSource extends jdbcDataSource implements DataSource { |
64 |
// 20090518 cmartinez: Use a different tmp dir for each geotools instance
|
65 |
private static File tmpDir = null; |
66 |
/**
|
67 |
* Creates a new instance of this data source
|
68 |
*/
|
69 |
public HSQLDataSource() {
|
70 |
File directory = getGtTmpDir();
|
71 |
if (directory.isDirectory() || directory.mkdir()) {
|
72 |
directory = new File(directory, "Cached databases"); |
73 |
if (directory.isDirectory() || directory.mkdir()) {
|
74 |
/*
|
75 |
* Constructs the full path to the HSQL database. Note: we do not use
|
76 |
* File.toURI() because HSQL doesn't seem to expect an encoded URL
|
77 |
* (e.g. "%20" instead of spaces).
|
78 |
*/
|
79 |
final StringBuffer url = new StringBuffer("jdbc:hsqldb:file:"); |
80 |
final String path = directory.getAbsolutePath().replace(File.separatorChar, '/'); |
81 |
if (path.length()==0 || path.charAt(0)!='/') { |
82 |
url.append('/');
|
83 |
} |
84 |
url.append(path); |
85 |
if (url.charAt(url.length()-1) != '/') { |
86 |
url.append('/');
|
87 |
} |
88 |
url.append("EPSG");
|
89 |
setDatabase(url.toString()); |
90 |
} |
91 |
/*
|
92 |
* If the temporary directory do not exists or can't be created,
|
93 |
* lets the 'database' attribute unset. If the user do not set it
|
94 |
* explicitly (for example through JNDI), an exception will be thrown
|
95 |
* when 'getConnection()' will be invoked.
|
96 |
*/
|
97 |
} |
98 |
setUser("SA"); // System administrator. No password. |
99 |
} |
100 |
|
101 |
private static File getGtTmpDir() { |
102 |
if (tmpDir == null) { |
103 |
tmpDir = new File(System.getProperty("java.io.tmpdir", "."), "Geotools-"+System.currentTimeMillis()); |
104 |
} |
105 |
return tmpDir;
|
106 |
} |
107 |
|
108 |
/**
|
109 |
* Returns the priority for this data source. This priority is set to a lower value than
|
110 |
* the {@linkplain AccessDataSource}'s one in order to give the priority to the Access-backed
|
111 |
* database, if presents. Priorities are set that way because:
|
112 |
* <ul>
|
113 |
* <li>The MS-Access format is the primary EPSG database format.</li>
|
114 |
* <li>If a user downloads the MS-Access database himself, he probably wants to use it.</li>
|
115 |
* </ul>
|
116 |
*/
|
117 |
public int getPriority() { |
118 |
return NORMAL_PRIORITY - 30; |
119 |
} |
120 |
|
121 |
/**
|
122 |
* Returns {@code true} if the database contains data. This method returns {@code false}
|
123 |
* if an empty EPSG database has been automatically created by HSQL and not yet populated.
|
124 |
*/
|
125 |
private static boolean dataExists(final Connection connection) throws SQLException { |
126 |
final ResultSet tables = connection.getMetaData().getTables( |
127 |
null, null, "EPSG_%", new String[] {"TABLE"}); |
128 |
final boolean exists = tables.next(); |
129 |
tables.close(); |
130 |
return exists;
|
131 |
} |
132 |
|
133 |
/**
|
134 |
* Opens a connection to the database. If the cached tables are not available,
|
135 |
* they will be created now from the SQL scripts bundled in this plugin.
|
136 |
*/
|
137 |
public Connection getConnection() throws SQLException { |
138 |
final String database = getDatabase(); |
139 |
if (database==null || database.trim().length()==0) { |
140 |
/*
|
141 |
* The 'database' attribute is unset if the constructor has been unable
|
142 |
* to locate the temporary directory, or to create the subdirectory.
|
143 |
*/
|
144 |
// TODO: localize
|
145 |
throw new SQLException("Can't write to the temporary directory."); |
146 |
} |
147 |
Connection connection = super.getConnection(); |
148 |
if (!dataExists(connection)) {
|
149 |
/*
|
150 |
* HSQL has created automatically an empty database. We need to populate it.
|
151 |
* Executes the SQL scripts bundled in the JAR. In theory, each line contains
|
152 |
* a full SQL statement. For this plugin however, we have compressed "INSERT
|
153 |
* INTO" statements using Compactor class in this package.
|
154 |
*/
|
155 |
Logger.getLogger("org.geotools.referencing.factory").config("Creating cached EPSG database."); // TODO: localize |
156 |
final Statement statement = connection.createStatement(); |
157 |
try {
|
158 |
final BufferedReader in = new BufferedReader(new InputStreamReader( |
159 |
HSQLDataSource.class.getResourceAsStream("EPSG.sql"), "ISO-8859-1")); |
160 |
StringBuffer insertStatement = null; |
161 |
String line;
|
162 |
while ((line=in.readLine()) != null) { |
163 |
line = line.trim(); |
164 |
final int length = line.length(); |
165 |
if (length != 0) { |
166 |
if (line.startsWith("INSERT INTO")) { |
167 |
/*
|
168 |
* We are about to insert many rows into a single table.
|
169 |
* The row values appear in next lines; the current line
|
170 |
* should stop right after the VALUES keyword.
|
171 |
*/
|
172 |
insertStatement = new StringBuffer(line); |
173 |
continue;
|
174 |
} |
175 |
if (insertStatement != null) { |
176 |
/*
|
177 |
* We are about to insert a row. Prepend the "INSERT INTO"
|
178 |
* statement and check if we will have more rows to insert
|
179 |
* after this one.
|
180 |
*/
|
181 |
final int values = insertStatement.length(); |
182 |
insertStatement.append(line); |
183 |
final boolean hasMore = (line.charAt(length-1) == ','); |
184 |
if (hasMore) {
|
185 |
insertStatement.setLength(insertStatement.length()-1);
|
186 |
} |
187 |
line = insertStatement.toString(); |
188 |
insertStatement.setLength(values); |
189 |
if (!hasMore) {
|
190 |
insertStatement = null;
|
191 |
} |
192 |
} |
193 |
statement.execute(line); |
194 |
} |
195 |
} |
196 |
in.close(); |
197 |
} catch (IOException exception) { |
198 |
statement.close(); |
199 |
SQLException e = new SQLException("Can't read the SQL script."); // TODO: localize |
200 |
e.initCause(exception); |
201 |
throw e;
|
202 |
} |
203 |
statement.close(); |
204 |
connection.close(); |
205 |
connection = super.getConnection();
|
206 |
assert dataExists(connection);
|
207 |
} |
208 |
return connection;
|
209 |
} |
210 |
|
211 |
/**
|
212 |
* Open a connection and creates an {@linkplain FactoryUsingSQL EPSG factory} for it.
|
213 |
*
|
214 |
* @param factories The low-level factories to use for CRS creation.
|
215 |
* @return The EPSG factory using HSQLDB SQL syntax.
|
216 |
* @throws SQLException if connection to the database failed.
|
217 |
*/
|
218 |
public AbstractAuthorityFactory createFactory(final FactoryGroup factories) throws SQLException { |
219 |
return new FactoryUsingHSQL(factories, getConnection()); |
220 |
} |
221 |
} |