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 @ 44950

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

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

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

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

    
143
    public static class ConnectionProvider {
144

    
145
        private static boolean needRegisterDriver = true;
146

    
147
        private BasicDataSource dataSource = null;
148

    
149
        private final H2SpatialConnectionParameters connectionParameters;
150
        
151
        private static Server server = null;
152
        private static boolean startServer = true;
153

    
154
        public ConnectionProvider(H2SpatialConnectionParameters connectionParameters) {
155
            this.connectionParameters = connectionParameters;
156
        }
157
        
158
        public static void stopServer() {
159
          try {
160
            server.shutdown();
161
          } catch(Throwable th) {
162
            
163
          }
164
          try {
165
            server.stop();
166
          } catch(Throwable th) {
167
            
168
          }
169
          server = null;
170
          startServer = true;
171
          LOGGER.info("H2 Server stopped" );
172
        }
173
        
174
        private void startServer() {
175
        
176
            if( startServer && server == null ) {
177
                String port = "9123";
178
                try {
179
                    Server theServer;
180
                    String s = System.getProperty("H2Port");
181
                    if( s!=null ) {
182
                        try {
183
                            int n = Integer.parseInt(s);
184
                            port = String.valueOf(n);
185
                        } catch(Throwable th) {
186
                            // Ignore port number, use default.
187
                        }
188
                    }
189
                    if( System.getProperty("H2AllowOthers")!=null ) {
190
                        theServer = Server.createTcpServer("-tcpPort", port, "-tcpAllowOthers", "-ifExists");
191
                    } else {
192
                        theServer = Server.createTcpServer("-tcpPort", port, "-ifExists");
193
                    }
194
                    theServer.start();
195
                    server = theServer;
196
                    LOGGER.info("H2 Server started" );
197
                    LOGGER.info("  port  :"+ server.getPort());
198
                    LOGGER.info("  URL  :"+ server.getURL());
199
                    LOGGER.info("  status:"+ server.getStatus());
200
                } catch (SQLException ex) {
201
                    LOGGER.warn("H2 Server not started",ex);
202
                }
203
                // Tanto si consigue lanzar el server como si no, no lo vuelve a intentar
204
                startServer = false;
205
            }
206

    
207
        }
208

    
209
        @Override
210
        public String toString() {
211
            StringBuilder builder = new StringBuilder();
212
            builder.append(" url=").append(connectionParameters.getUrl());
213
            builder.append(" driver name=").append(connectionParameters.getJDBCDriverClassName());
214
            builder.append(" user=").append(connectionParameters.getUser());
215
            return builder.toString();
216
        }
217
        
218
        public Connection getConnection() throws SQLException {
219
            File f = getLocalFile(connectionParameters);
220
            boolean newdb = f != null && !f.exists();
221

    
222
            if (this.dataSource == null) {
223
                this.dataSource = this.createDataSource();               
224
            }
225
            Connection conn = this.dataSource.getConnection();
226
            try {
227
                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
228
            } catch(SQLException ex) {
229
                H2GISExtension.load(conn);
230
            }
231
            try {
232
                conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC");
233
            } catch(SQLException ex) {
234
                // Ignore this error.
235
            }
236
            return conn;
237
        }
238

    
239
        private BasicDataSource createDataSource() throws SQLException {
240
            if (!this.isRegistered()) {
241
                this.registerDriver();
242
            }
243
            startServer();
244
            H2SpatialConnectionParameters params = connectionParameters;
245

    
246
            BasicDataSource ds = new BasicDataSource();
247
            ds.setDriverClassName(params.getJDBCDriverClassName());
248
            if( !StringUtils.isEmpty(params.getUser()) ) {
249
                ds.setUsername(params.getUser());
250
            }
251
            if( !StringUtils.isEmpty(params.getPassword()) ) {
252
                ds.setPassword(params.getPassword());
253
            }
254
            ds.setUrl(params.getUrl());
255

    
256
            ds.setMaxWait(60L * 1000);
257
            return ds;
258
        }
259

    
260
        private boolean isRegistered() {
261
            return needRegisterDriver;
262
        }
263

    
264
        public void registerDriver() throws SQLException {
265
            String className = this.connectionParameters.getJDBCDriverClassName();
266
            if (className == null) {
267
                return;
268
            }
269
            try {
270
                Class theClass = Class.forName(className);
271
                if (theClass == null) {
272
                    throw new JDBCDriverClassNotFoundException(H2SpatialLibrary.NAME, className);
273
                }
274
            } catch (Exception e) {
275
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
276
            }
277
            needRegisterDriver = false;
278
        }
279

    
280
    }
281

    
282
    private ConnectionProvider connectionProvider = null;
283
 
284
    /**
285
     * Constructor for use only for testing purposes.
286
     */
287
    public H2SpatialHelper() { 
288
        super(null);
289
    }
290
  
291
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters) {
292
        super(connectionParameters);
293
        this.srssolver = new SRSSolverBase(this);
294
    }
295

    
296
    @Override
297
    public synchronized Connection  getConnection() throws AccessResourceException {
298
        try {
299
            if (this.connectionProvider == null) {
300
              H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
301
              if( connectionParameters==null ) {
302
                return null; // Testing mode?
303
              }
304
              this.connectionProvider = new ConnectionProvider(connectionParameters);
305
            }
306
            Connection connection = this.connectionProvider.getConnection();
307
            if( LOGGER.isDebugEnabled() ) {
308
                LOGGER.debug("getConnection: connection = "+connection.hashCode()+ connectionProvider.toString());
309
            }
310
            return connection;
311
        } catch (SQLException ex) {
312
            throw new AccessResourceException(H2SpatialLibrary.NAME, ex);
313
        }
314
    }
315

    
316
    @Override
317
    public void closeConnection(Connection connection) {
318
      if( connection!=null ) { // In test ???
319
        LOGGER.debug("closeConnection: connection = "+connection.hashCode());
320
      }
321
      super.closeConnection(connection);
322
    }
323
    
324
    @Override
325
    public H2SpatialConnectionParameters getConnectionParameters() {
326
        return (H2SpatialConnectionParameters) super.getConnectionParameters();
327
    }
328
    
329
    @Override
330
    public String getConnectionURL() {
331
        return getConnectionURL(this.getConnectionParameters());
332
    }
333

    
334
    @Override
335
    protected String getResourceType() {
336
        return H2SpatialLibrary.NAME;
337
    }
338

    
339
    @Override
340
    public String getProviderName() {
341
        return H2SpatialLibrary.NAME;
342
    }
343

    
344
    @Override
345
    public JDBCSQLBuilderBase createSQLBuilder() {
346
        return new H2SpatialSQLBuilder(this);
347
    }
348
    
349
    @Override
350
    public OperationsFactory getOperations() {
351
        if (this.operationsFactory == null) {
352
            this.operationsFactory = new H2SpatialOperationsFactory(this);
353
        }
354
        return operationsFactory;
355
    }
356

    
357
    @Override
358
    public GeometrySupportType getGeometrySupportType() {
359
        return GeometrySupportType.WKB;
360
    }
361

    
362
    @Override
363
    public boolean hasSpatialFunctions() {
364
        return true;
365
    }
366

    
367
    @Override
368
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
369
        return true;
370
    }
371

    
372
    @Override
373
    public String getQuoteForIdentifiers() {
374
        return "\"";
375
    }
376

    
377
    @Override
378
    public boolean allowAutomaticValues() {
379
        return true;
380
    }
381

    
382
    @Override
383
    public boolean supportOffsetInSelect() {
384
        return true;
385
    }
386

    
387
    @Override
388
    public String getQuoteForStrings() {
389
        return "'";
390
    }
391

    
392
    @Override
393
    public String getSourceId(JDBCStoreParameters parameters) {
394
        return parameters.getDBName() + "." + 
395
               parameters.getSchema()+ "." + 
396
               parameters.getTable();
397
    }
398

    
399
    @Override
400
    public JDBCNewStoreParameters createNewStoreParameters() {
401
        return new H2SpatialNewStoreParameters();
402
    }
403

    
404
    @Override
405
    public JDBCStoreParameters createOpenStoreParameters() {
406
        return new H2SpatialStoreParameters();
407
    }
408

    
409
    @Override
410
    public JDBCServerExplorerParameters createServerExplorerParameters() {
411
        return new H2SpatialExplorerParameters();
412
    }
413

    
414
    @Override
415
    public JDBCServerExplorer createServerExplorer(
416
            JDBCServerExplorerParameters parameters, 
417
            DataServerExplorerProviderServices providerServices
418
        ) throws InitializeException {
419
        
420
        JDBCServerExplorer explorer = new JDBCServerExplorerBase(
421
                parameters, 
422
                providerServices, 
423
                this
424
        );
425
        this.initialize(explorer, parameters, null);
426
        return explorer;
427
    }
428
}