Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.h2 / src / main / java / org / gvsig / fmap / dal / store / h2 / H2SpatialHelper.java @ 44841

History | View | Annotate | Download (14.3 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2016 Infrastructures and Transports Department
4
 * of the Valencian Government (CIT)
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 */
22
package org.gvsig.fmap.dal.store.h2;
23

    
24
import java.sql.Connection;
25
import java.sql.SQLException;
26
import java.text.MessageFormat;
27
import org.apache.commons.dbcp.BasicDataSource;
28
import org.apache.commons.io.FilenameUtils;
29
import org.apache.commons.lang3.StringUtils;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import org.gvsig.fmap.dal.exception.InitializeException;
32
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
33
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
34
import org.gvsig.fmap.dal.store.h2.operations.H2SpatialOperationsFactory;
35
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
36
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
37
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
38
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
39
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
40
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
41
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
42
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
43
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
44
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCServerExplorerBase;
45
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
46
import org.h2.tools.Server;
47
import org.h2gis.ext.H2GISExtension;
48
import org.slf4j.Logger;
49
import org.slf4j.LoggerFactory;
50

    
51
@SuppressWarnings("UseSpecificCatch")
52
public class H2SpatialHelper extends JDBCHelperBase {
53

    
54
    static final Logger LOGGER = LoggerFactory.getLogger(H2SpatialHelper.class);
55

    
56
    public static final String H2SPATIAL_JDBC_DRIVER = "org.h2.Driver";
57
    
58
    public static String getConnectionURL(H2SpatialConnectionParameters params) {
59
        String connectionURL;
60
        String dbfilename = params.getFile().getAbsolutePath().replace("\\","/");
61
        if( dbfilename!=null && dbfilename.endsWith(".mv.db") ) {
62
            dbfilename = dbfilename.substring(0, dbfilename.length()-6);
63
        }
64
        StringBuilder commonParameters = new StringBuilder();
65
        commonParameters.append(";MODE=PostgreSQL");
66
        commonParameters.append(";SCHEMA=PUBLIC");
67
        commonParameters.append(";ALLOW_LITERALS=ALL");
68
        
69
//        Integer LOCK_TIMEOUT = (Integer) params.getDynValue("LOCK_TIMEOUT");
70
//        if( LOCK_TIMEOUT!=null ) {
71
//            commonParameters.append(";LOCK_TIMEOUT=").append(LOCK_TIMEOUT);
72
//        }
73
//        Integer MULTI_THREADED = (Integer) params.getDynValue("MULTI_THREADED");
74
//        if( MULTI_THREADED!=null ) {
75
//            commonParameters.append(";MULTI_THREADED=").append(MULTI_THREADED);
76
//        }
77
//        Integer CHACHE_SIZE = (Integer) params.getDynValue("CHACHE_SIZE");
78
//        if( LOCK_TIMEOUT!=null ) {
79
//            commonParameters.append(";CHACHE_SIZE=").append(CHACHE_SIZE);
80
//        }
81
//        Integer LOG = (Integer) params.getDynValue("LOG");
82
//        if( LOCK_TIMEOUT!=null ) {
83
//            commonParameters.append(";LOG=").append(LOG);
84
//        }
85
//        Integer LOCK_MODE = (Integer) params.getDynValue("LOCK_MODE");
86
//        if( LOCK_TIMEOUT!=null ) {
87
//            commonParameters.append(";LOCK_MODE=").append(LOCK_MODE);
88
//        }
89
        
90
        if( StringUtils.isEmpty(params.getHost()) ) {
91
            // Asumimos que es una conexion directa sobre el filesystem
92
            if( StringUtils.equalsIgnoreCase(FilenameUtils.getExtension(params.getFile().getName()),"zip") ) {
93
                connectionURL =  MessageFormat.format(
94
                    "jdbc:h2:zip:{0}!/{1}"+commonParameters.toString(),
95
                    dbfilename,
96
                    params.getDBName()
97
                );
98
            } else {
99
                connectionURL =  MessageFormat.format(
100
                    "jdbc:h2:file:{0}"+commonParameters.toString(),
101
                    dbfilename
102
                );
103
            }
104
        } else if( params.getPort() == null ) {
105
            connectionURL =  MessageFormat.format(
106
                "jdbc:h2:tcp://{0}/{1}"+commonParameters.toString(),
107
                params.getHost(),
108
                dbfilename
109
            );            
110
        } else {
111
            connectionURL =  MessageFormat.format(                
112
                "jdbc:h2:tcp://{0}:{1,number,#######}/{2}"+commonParameters.toString(),
113
                params.getHost(),
114
                params.getPort().intValue(),
115
                dbfilename
116
            );
117
        }
118
        LOGGER.debug("connectionURL: {}", connectionURL);
119
        return connectionURL;
120
    }
121

    
122
    public static class ConnectionProvider {
123

    
124
        private static boolean needRegisterDriver = true;
125

    
126
        private BasicDataSource dataSource = null;
127

    
128
        private final H2SpatialConnectionParameters connectionParameters;
129

    
130
        private static Server server = null;
131
        private static boolean startServer = true;
132

    
133
        public ConnectionProvider(H2SpatialConnectionParameters connectionParameters) {
134
            this.connectionParameters = connectionParameters;
135
        }
136
        
137
        public static void stopServer() {
138
          try {
139
            server.shutdown();
140
          } catch(Throwable th) {
141
            
142
          }
143
          try {
144
            server.stop();
145
          } catch(Throwable th) {
146
            
147
          }
148
          server = null;
149
          startServer = true;
150
          LOGGER.info("H2 Server stopped" );
151
        }
152
        
153
        private void startServer() {
154
        
155
            if( startServer && server == null ) {
156
                String port = "9123";
157
                try {
158
                    Server theServer;
159
                    String s = System.getProperty("H2Port");
160
                    if( s!=null ) {
161
                        try {
162
                            int n = Integer.parseInt(s);
163
                            port = String.valueOf(n);
164
                        } catch(Throwable th) {
165
                            // Ignore port number, use default.
166
                        }
167
                    }
168
                    if( System.getProperty("H2AllowOthers")!=null ) {
169
                        theServer = Server.createTcpServer("-tcpPort", port, "-tcpAllowOthers", "-ifExists");
170
                    } else {
171
                        theServer = Server.createTcpServer("-tcpPort", port, "-ifExists");
172
                    }
173
                    theServer.start();
174
                    server = theServer;
175
                    LOGGER.info("H2 Server started" );
176
                    LOGGER.info("  port  :"+ server.getPort());
177
                    LOGGER.info("  URL  :"+ server.getURL());
178
                    LOGGER.info("  status:"+ server.getStatus());
179
                } catch (SQLException ex) {
180
                    LOGGER.warn("H2 Server not started",ex);
181
                }
182
                // Tanto si consigue lanzar el server como si no, no lo vuelve a intentar
183
                startServer = false;
184
            }
185

    
186
        }
187

    
188
        @Override
189
        public String toString() {
190
            StringBuilder builder = new StringBuilder();
191
            builder.append(" url=").append(connectionParameters.getUrl());
192
            builder.append(" driver name=").append(connectionParameters.getJDBCDriverClassName());
193
            builder.append(" user=").append(connectionParameters.getUser());
194
            return builder.toString();
195
        }
196
        
197
        public Connection getConnection() throws SQLException {
198
            if (this.dataSource == null) {
199
                this.dataSource = this.createDataSource();               
200
            }
201
            Connection conn = this.dataSource.getConnection();
202
            try {
203
                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
204
            } catch(SQLException ex) {
205
                H2GISExtension.load(conn);
206
            }
207
            try {
208
                conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC");
209
            } catch(SQLException ex) {
210
                // Ignore this error.
211
            }
212

    
213
            return conn;
214
        }
215

    
216
        private BasicDataSource createDataSource() throws SQLException {
217
            if (!this.isRegistered()) {
218
                this.registerDriver();
219
            }
220
            startServer();
221
            H2SpatialConnectionParameters params = connectionParameters;
222

    
223
            BasicDataSource ds = new BasicDataSource();
224
            ds.setDriverClassName(params.getJDBCDriverClassName());
225
            if( !StringUtils.isEmpty(params.getUser()) ) {
226
                ds.setUsername(params.getUser());
227
            }
228
            if( !StringUtils.isEmpty(params.getPassword()) ) {
229
                ds.setPassword(params.getPassword());
230
            }
231
            ds.setUrl(params.getUrl());
232

    
233
            ds.setMaxWait(60L * 1000);
234
            return ds;
235
        }
236

    
237
        private boolean isRegistered() {
238
            return needRegisterDriver;
239
        }
240

    
241
        public void registerDriver() throws SQLException {
242
            String className = this.connectionParameters.getJDBCDriverClassName();
243
            if (className == null) {
244
                return;
245
            }
246
            try {
247
                Class theClass = Class.forName(className);
248
                if (theClass == null) {
249
                    throw new JDBCDriverClassNotFoundException(H2SpatialLibrary.NAME, className);
250
                }
251
            } catch (Exception e) {
252
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
253
            }
254
            needRegisterDriver = false;
255
        }
256

    
257
    }
258

    
259
    private ConnectionProvider connectionProvider = null;
260
 
261
    /**
262
     * Constructor for use only for testing purposes.
263
     */
264
    public H2SpatialHelper() { 
265
        super(null);
266
    }
267
  
268
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters) {
269
        super(connectionParameters);
270
        this.srssolver = new SRSSolverBase(this);
271
    }
272

    
273
    @Override
274
    public synchronized Connection  getConnection() throws AccessResourceException {
275
        try {
276
            if (this.connectionProvider == null) {
277
              H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
278
              if( connectionParameters==null ) {
279
                return null; // Testing mode?
280
              }
281
              this.connectionProvider = new ConnectionProvider(connectionParameters);
282
            }
283
            Connection connection = this.connectionProvider.getConnection();
284
            if( LOGGER.isDebugEnabled() ) {
285
                LOGGER.debug("getConnection: connection = "+connection.hashCode()+ connectionProvider.toString());
286
            }
287
            return connection;
288
        } catch (SQLException ex) {
289
            throw new AccessResourceException(H2SpatialLibrary.NAME, ex);
290
        }
291
    }
292

    
293
    @Override
294
    public void closeConnection(Connection connection) {
295
      if( connection!=null ) { // In test ???
296
        LOGGER.debug("closeConnection: connection = "+connection.hashCode());
297
      }
298
      super.closeConnection(connection);
299
    }
300
    
301
    @Override
302
    public H2SpatialConnectionParameters getConnectionParameters() {
303
        return (H2SpatialConnectionParameters) super.getConnectionParameters();
304
    }
305
    
306
    @Override
307
    public String getConnectionURL() {
308
        return getConnectionURL(this.getConnectionParameters());
309
    }
310

    
311
    @Override
312
    protected String getResourceType() {
313
        return H2SpatialLibrary.NAME;
314
    }
315

    
316
    @Override
317
    public String getProviderName() {
318
        return H2SpatialLibrary.NAME;
319
    }
320

    
321
    @Override
322
    public JDBCSQLBuilderBase createSQLBuilder() {
323
        return new H2SpatialSQLBuilder(this);
324
    }
325
    
326
    @Override
327
    public OperationsFactory getOperations() {
328
        if (this.operationsFactory == null) {
329
            this.operationsFactory = new H2SpatialOperationsFactory(this);
330
        }
331
        return operationsFactory;
332
    }
333

    
334
    @Override
335
    public GeometrySupportType getGeometrySupportType() {
336
        return GeometrySupportType.WKB;
337
    }
338

    
339
    @Override
340
    public boolean hasSpatialFunctions() {
341
        return true;
342
    }
343

    
344
    @Override
345
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
346
        return true;
347
    }
348

    
349
    @Override
350
    public String getQuoteForIdentifiers() {
351
        return "\"";
352
    }
353

    
354
    @Override
355
    public boolean allowAutomaticValues() {
356
        return true;
357
    }
358

    
359
    @Override
360
    public boolean supportOffsetInSelect() {
361
        return true;
362
    }
363

    
364
    @Override
365
    public String getQuoteForStrings() {
366
        return "'";
367
    }
368

    
369
    @Override
370
    public String getSourceId(JDBCStoreParameters parameters) {
371
        return parameters.getDBName() + "." + 
372
               parameters.getSchema()+ "." + 
373
               parameters.getTable();
374
    }
375

    
376
    @Override
377
    public JDBCNewStoreParameters createNewStoreParameters() {
378
        return new H2SpatialNewStoreParameters();
379
    }
380

    
381
    @Override
382
    public JDBCStoreParameters createOpenStoreParameters() {
383
        return new H2SpatialStoreParameters();
384
    }
385

    
386
    @Override
387
    public JDBCServerExplorerParameters createServerExplorerParameters() {
388
        return new H2SpatialExplorerParameters();
389
    }
390

    
391
    @Override
392
    public JDBCServerExplorer createServerExplorer(
393
            JDBCServerExplorerParameters parameters, 
394
            DataServerExplorerProviderServices providerServices
395
        ) throws InitializeException {
396
        
397
        JDBCServerExplorer explorer = new JDBCServerExplorerBase(
398
                parameters, 
399
                providerServices, 
400
                this
401
        );
402
        this.initialize(explorer, parameters, null);
403
        return explorer;
404
    }
405
}