Revision 238 org.gvsig.projection.jcrs/trunk/org.gvsig.projection.jcrs/org.gvsig.projection.jcrs.lib/src/main/java/es/idr/teledeteccion/connection/epsg/HSQLDataSource.java

View differences:

HSQLDataSource.java
42 42
import org.slf4j.Logger;
43 43
import org.slf4j.LoggerFactory;
44 44

  
45

  
46 45
/**
47
 * Connection to the EPSG database in HSQL database engine format using JDBC. The EPSG
48
 * database can be downloaded from <A HREF="http://www.epsg.org">http://www.epsg.org</A>.
49
 * The SQL scripts (modified for the HSQL syntax as <A HREF="doc-files/HSQL.html">explained
50
 * here</A>) are bundled into this plugin. The database version is given in the
46
 * Connection to the EPSG database in HSQL database engine format using JDBC.
47
 * The EPSG database can be downloaded from <A
48
 * HREF="http://www.epsg.org">http://www.epsg.org</A>. The SQL scripts (modified
49
 * for the HSQL syntax as <A HREF="doc-files/HSQL.html">explained here</A>) are
50
 * bundled into this plugin. The database version is given in the
51 51
 * {@linkplain org.opengis.metadata.citation.Citation#getEdition edition attribute}
52
 * of the {@linkplain org.opengis.referencing.AuthorityFactory#getAuthority authority}.
52
 * of the
53
 * {@linkplain org.opengis.referencing.AuthorityFactory#getAuthority authority}.
53 54
 * The HSQL database is read only.
54 55
 * <P>
55 56
 * <H3>Implementation note</H3>
56
 * The SQL scripts are executed the first time a connection is required. The database
57
 * is then created as cached tables ({@code HSQL.properties} and {@code HSQL.data} files)
58
 * in a temporary directory. Future connections to the EPSG database while reuse the cached
59
 * tables, if available. Otherwise, the scripts will be executed again in order to recreate
60
 * them.
57
 * The SQL scripts are executed the first time a connection is required. The
58
 * database is then created as cached tables ({@code HSQL.properties} and
59
 * {@code HSQL.data} files) in a temporary directory. Future connections to the
60
 * EPSG database while reuse the cached tables, if available. Otherwise, the
61
 * scripts will be executed again in order to recreate them.
61 62
 *
62 63
 * @version $Id: HSQLDataSource.java 14624 2005-06-29 02:19:08Z desruisseaux $
63 64
 * @author Martin Desruisseaux
......
66 67
 * @since 2.2
67 68
 */
68 69
public class HSQLDataSource extends jdbcDataSource implements DataSource {
69
	// 20090518 cmartinez: Use a different tmp dir for each geotools instance
70
	private static File tmpDir = null;
71
	
72
	private static final Logger logger = LoggerFactory.getLogger(HSQLDataSource.class);
70

  
71
    // 20090518 cmartinez: Use a different tmp dir for each geotools instance
72
    private static File tmpDir = null;
73

  
74
    private static final Logger logger = LoggerFactory.getLogger(HSQLDataSource.class);
75

  
73 76
    /**
74 77
     * Creates a new instance of this data source
75 78
     */
......
85 88
                 */
86 89
                final StringBuffer url = new StringBuffer("jdbc:hsqldb:file:");
87 90
                final String path = directory.getAbsolutePath().replace(File.separatorChar, '/');
88
                if (path.length()==0 || path.charAt(0)!='/') {
91
                if (path.length() == 0 || path.charAt(0) != '/') {
89 92
                    url.append('/');
90 93
                }
91 94
                url.append(path);
92
                if (url.charAt(url.length()-1) != '/') {
95
                if (url.charAt(url.length() - 1) != '/') {
93 96
                    url.append('/');
94 97
                }
95 98
                url.append("EPSG");
......
105 108
        setUser("SA"); // System administrator. No password.
106 109
    }
107 110

  
108
    private static File getGtTmpDir() {
109
    	if (tmpDir == null) {
110
//    		tmpDir = new File(System.getProperty("java.io.tmpdir", "."), "Geotools-"+System.currentTimeMillis());
111
    		tmpDir = new File( CrsFactory.getDataBaseFolder(),"temp-"+ getProcessId());
112
    		Runtime.getRuntime().addShutdownHook( new RemoveFolderOnShutdown(tmpDir) );
113
    	}
114
    	return tmpDir;
111
    private File getGtTmpDir() {
112
        if (tmpDir == null) {
113
            tmpDir = new File(CrsFactory.getDataBaseFolder(), "temp-" + getProcessId());
114
            Runtime.getRuntime().addShutdownHook(new cleanOnShutdown(this));
115
        }
116
        return tmpDir;
115 117
    }
116 118

  
117 119
    private static String getProcessId() {
118
    	String fallback = "time" + System.currentTimeMillis();
119
    	
120
        String fallback = "time" + System.currentTimeMillis();
121

  
120 122
        // something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
121 123
        final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
122 124
        final int index = jvmName.indexOf('@');
......
125 127
            return fallback;
126 128
        }
127 129
        try {
128
            return "pid"+Long.toString(Long.parseLong(jvmName.substring(0, index)));
130
            return "pid" + Long.toString(Long.parseLong(jvmName.substring(0, index)));
129 131
        } catch (NumberFormatException e) {
130 132
            // ignore
131 133
        }
132 134
        return fallback;
133 135
    }
134
    
135
    public static class RemoveFolderOnShutdown extends Thread {
136
    	private File folder;
137
		public RemoveFolderOnShutdown(File folder) {
138
    		this.folder = folder;
139
    	}
140
    	public void run() {
141
    		try {
142
    			logger.info("Deleting CRS temporary database folder ("+folder.getAbsolutePath()+").");
143
				FileUtils.deleteDirectory(this.folder);
144
			} catch (IOException e) {
145
				logger.error("Can't delete CRS temporary database folder ("+this.folder+".",e);
146
			}
147
    	}
136

  
137
    public static class cleanOnShutdown extends Thread {
138

  
139
        private HSQLDataSource ds;
140

  
141
        public cleanOnShutdown(HSQLDataSource ds) {
142
            this.ds = ds;
143
        }
144

  
145
        public void run() {
146
            this.shutdown();
147
            this.delete();
148
        }
149

  
150
        private void delete() {
151
            File folder = HSQLDataSource.tmpDir;
152
            if (folder == null) {
153
                return;
154
            }
155
            try {
156
                logger.info("Deleting CRS temporary database folder (" + folder.getAbsolutePath() + ").");
157
                FileUtils.deleteDirectory(folder);
158
            } catch (IOException e) {
159
                logger.error("Can't delete CRS temporary database folder (" + folder + ".", e);
160
            }
161
        }
162

  
163
        private void shutdown() {
164
            try {
165
                logger.info("Shutdown the data-base.");
166
                Connection connection = this.ds.getConnection(false);
167
                final Statement statement = connection.createStatement();
168
                statement.execute("SHUTDOWN");
169
                statement.close();
170
                connection.close();
171
            } catch (Exception ex) {
172
                logger.error("Can't shutdown the database.", ex);
173
            }
174
        }
148 175
    }
149
    
176

  
150 177
    /**
151
     * Returns the priority for this data source. This priority is set to a lower value than
152
     * the {@linkplain AccessDataSource}'s one in order to give the priority to the Access-backed
153
     * database, if presents. Priorities are set that way because:
178
     * Returns the priority for this data source. This priority is set to a
179
     * lower value than the {@linkplain AccessDataSource}'s one in order to give
180
     * the priority to the Access-backed database, if presents. Priorities are
181
     * set that way because:
154 182
     * <ul>
155
     *   <li>The MS-Access format is the primary EPSG database format.</li>
156
     *   <li>If a user downloads the MS-Access database himself, he probably wants to use it.</li>
183
     * <li>The MS-Access format is the primary EPSG database format.</li>
184
     * <li>If a user downloads the MS-Access database himself, he probably wants
185
     * to use it.</li>
157 186
     * </ul>
158 187
     */
159 188
    public int getPriority() {
......
161 190
    }
162 191

  
163 192
    /**
164
     * Returns {@code true} if the database contains data. This method returns {@code false}
165
     * if an empty EPSG database has been automatically created by HSQL and not yet populated.
193
     * Returns {@code true} if the database contains data. This method returns
194
     * {@code false} if an empty EPSG database has been automatically created by
195
     * HSQL and not yet populated.
166 196
     */
167 197
    private static boolean dataExists(final Connection connection) throws SQLException {
168 198
        final ResultSet tables = connection.getMetaData().getTables(
169
                null, null, "EPSG_%", new String[] {"TABLE"});
199
                null, null, "EPSG_%", new String[]{"TABLE"});
170 200
        final boolean exists = tables.next();
171 201
        tables.close();
172 202
        return exists;
173 203
    }
174 204

  
175 205
    /**
176
     * Opens a connection to the database. If the cached tables are not available,
177
     * they will be created now from the SQL scripts bundled in this plugin.
206
     * Opens a connection to the database. If the cached tables are not
207
     * available, they will be created now from the SQL scripts bundled in this
208
     * plugin.
178 209
     */
179 210
    public Connection getConnection() throws SQLException {
211
        return getConnection(true);
212
    }
213

  
214
    public Connection getConnection(boolean initialize) throws SQLException {
180 215
        final String database = getDatabase();
181
        if (database==null || database.trim().length()==0) {
216
        if (database == null || database.trim().length() == 0) {
182 217
            /*
183 218
             * The 'database' attribute is unset if the constructor has been unable
184 219
             * to locate the temporary directory, or to create the subdirectory.
185 220
             */
186
            // TODO: localize
187 221
            throw new SQLException("Can't write to the temporary directory.");
188 222
        }
189 223
        Connection connection = super.getConnection();
224
        if (!initialize) {
225
            return connection;
226
        }
190 227
        if (!dataExists(connection)) {
191 228
            /*
192 229
             * HSQL has created automatically an empty database. We need to populate it.
......
194 231
             * a full SQL statement. For this plugin however, we have compressed "INSERT
195 232
             * INTO" statements using Compactor class in this package.
196 233
             */
197
            logger.info("Creating temporary cached EPSG database in '"+getGtTmpDir().getAbsolutePath()+"'."); 
234
            logger.info("Creating temporary cached EPSG database in '" + getGtTmpDir().getAbsolutePath() + "'.");
198 235
            final Statement statement = connection.createStatement();
199 236
            try {
200
                FileInputStream sqlInputStream = new FileInputStream(new File(CrsFactory.getDataBaseFolder(),"EPSG.sql"));
237
                FileInputStream sqlInputStream = new FileInputStream(new File(CrsFactory.getDataBaseFolder(), "EPSG.sql"));
201 238
                final BufferedReader in = new BufferedReader(new InputStreamReader(
202
                		sqlInputStream, "ISO-8859-1"));
203
                
204
//                final BufferedReader in = new BufferedReader(new InputStreamReader(
205
//                        HSQLDataSource.class.getResourceAsStream("EPSG.sql"), "ISO-8859-1"));
206

  
207
                
239
                        sqlInputStream, "ISO-8859-1"));
208 240
                StringBuffer insertStatement = null;
209 241
                String line;
210
                while ((line=in.readLine()) != null) {
242
                while ((line = in.readLine()) != null) {
211 243
                    line = line.trim();
212 244
                    final int length = line.length();
213 245
                    if (length != 0) {
......
228 260
                             */
229 261
                            final int values = insertStatement.length();
230 262
                            insertStatement.append(line);
231
                            final boolean hasMore = (line.charAt(length-1) == ',');
263
                            final boolean hasMore = (line.charAt(length - 1) == ',');
232 264
                            if (hasMore) {
233
                                insertStatement.setLength(insertStatement.length()-1);
265
                                insertStatement.setLength(insertStatement.length() - 1);
234 266
                            }
235 267
                            line = insertStatement.toString();
236 268
                            insertStatement.setLength(values);
......
244 276
                in.close();
245 277
            } catch (IOException exception) {
246 278
                statement.close();
247
                SQLException e = new SQLException("Can't read the SQL script."); // TODO: localize
279
                SQLException e = new SQLException("Can't read the SQL script.");
248 280
                e.initCause(exception);
249 281
                throw e;
250 282
            }
......
257 289
    }
258 290

  
259 291
    /**
260
     * Open a connection and creates an {@linkplain FactoryUsingSQL EPSG factory} for it.
292
     * Open a connection and creates an
293
     * {@linkplain FactoryUsingSQL EPSG factory} for it.
261 294
     *
262
     * @param  factories The low-level factories to use for CRS creation.
295
     * @param factories The low-level factories to use for CRS creation.
263 296
     * @return The EPSG factory using HSQLDB SQL syntax.
264 297
     * @throws SQLException if connection to the database failed.
265 298
     */
266 299
    public AbstractAuthorityFactory createFactory(final FactoryGroup factories) throws SQLException {
267 300
        return new FactoryUsingHSQL(factories, getConnection());
268 301
    }
269
    
302

  
270 303
    public java.util.logging.Logger getParentLogger()
271
    		throws SQLFeatureNotSupportedException {
272
    	// TODO Auto-generated method stub
273
    	return null;
304
            throws SQLFeatureNotSupportedException {
305
        // TODO Auto-generated method stub
306
        return null;
274 307
    }
275
    
308

  
276 309
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
277
    	// TODO Auto-generated method stub
278
    	return false;
310
        // TODO Auto-generated method stub
311
        return false;
279 312
    }
280
    
313

  
281 314
    public <T> T unwrap(Class<T> iface) throws SQLException {
282
    	// TODO Auto-generated method stub
283
    	return null;
315
        // TODO Auto-generated method stub
316
        return null;
284 317
    }
285 318
}

Also available in: Unified diff