Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.h2spatial / org.gvsig.h2spatial.h2gis132 / org.gvsig.h2spatial.h2gis132.provider / src / main / java / org / gvsig / fmap / dal / store / h2 / H2SpatialHelper.java @ 45901

History | View | Annotate | Download (18.4 KB)

1
/* gvSIG. Geographic Information System of the Valencian Government
2
 *
3
 * Copyright (C) 2007-2020 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.DriverManager;
27
import java.sql.SQLException;
28
import org.apache.commons.dbcp.BasicDataSource;
29
import org.apache.commons.lang3.StringUtils;
30
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
31
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
32
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
33
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_NAME;
34
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_RESOURCE;
35
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_CONFIGURATION_NAME;
36
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
37
import org.gvsig.fmap.dal.exception.InitializeException;
38
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
39
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
40
import static org.gvsig.fmap.dal.store.h2.H2SpatialHelper.LOGGER;
41
import org.gvsig.fmap.dal.store.h2.operations.H2SpatialOperationsFactory;
42
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
43
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
44
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
45
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
46
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
47
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
48
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
49
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
55
import org.h2.tools.Server;
56
import org.h2gis.functions.factory.H2GISFunctions;
57
import org.h2gis.functions.system.H2GISversion;
58
import org.slf4j.Logger;
59
import org.slf4j.LoggerFactory;
60

    
61

    
62
@SuppressWarnings("UseSpecificCatch")
63
public class H2SpatialHelper extends JDBCHelperBase {
64

    
65
    static final Logger LOGGER = LoggerFactory.getLogger(H2SpatialHelper.class);
66

    
67
    public static final String H2SPATIAL_JDBC_DRIVER = "org.h2.Driver";
68
    
69
    public static class ConnectionProviderImpl implements ConnectionProvider {
70

    
71
        private static boolean needRegisterDriver = true;
72

    
73
        private BasicDataSource dataSource = null;
74

    
75
        private H2SpatialConnectionParameters connectionParameters;
76
        
77
        public ConnectionProviderImpl(H2SpatialConnectionParameters connectionParameters) {
78
            this.connectionParameters = connectionParameters;
79
        }
80

    
81
        @Override
82
        public String getStatus() {
83
            if(dataSource == null) {
84
                return "Not using pool.";
85
            }
86
            StringBuilder builder = new StringBuilder();
87
            builder.append("Pool: ");
88
            builder.append(JDBCUtils.getHexId(dataSource));
89
            builder.append(" Actives: ");
90
            builder.append(dataSource.getNumActive());
91
            builder.append("/");
92
            builder.append(dataSource.getMaxActive());
93
            builder.append(" idle: ");
94
            builder.append(dataSource.getNumIdle());
95
            builder.append("/");
96
            builder.append(dataSource.getMinIdle());
97
            builder.append(":");
98
            builder.append(dataSource.getMaxIdle());
99
            return builder.toString();
100
        }
101
        
102
        @SuppressWarnings("ConvertToTryWithResources")
103
        public void shutdown() {
104
            LOGGER.info("Shutdown H2 connection.");
105
            try {
106
                Connection conn = this.getConnection();
107
                conn.createStatement().execute("SHUTDOWN");
108
                conn.close();
109
            } catch (Throwable th) {
110
                LOGGER.warn("Problems shutdown the database.", th);
111
            }
112
            closeDataSource();
113
        }
114
        
115
        @Override
116
        public String toString() {
117
            StringBuilder builder = new StringBuilder();
118
            builder.append(" url=").append(connectionParameters.getUrl());
119
            builder.append(" driver name=").append(connectionParameters.getJDBCDriverClassName());
120
            builder.append(" user=").append(connectionParameters.getUser());
121
            return builder.toString();
122
        }
123
        
124
        @Override
125
        public synchronized Connection getConnection() throws SQLException {
126
            File f = H2SpatialUtils.getLocalFile(connectionParameters);
127
            boolean newdb = !f.exists();
128
            
129
            Connection conn;
130
            
131
            try {
132
                conn = DriverManager.getConnection(
133
                    connectionParameters.getUrl(), 
134
                    connectionParameters.getUser(), 
135
                    connectionParameters.getPassword()
136
                );
137

    
138
            } catch(Throwable th) {
139
                throw th;
140
            }
141
            
142
            H2SpatialUtils.server_start(
143
                    this.connectionParameters.getServerPortAsString(), 
144
                    this.connectionParameters.getServerAllowOthers()
145
            );
146
            
147
//            if (this.dataSource == null) {
148
//                this.dataSource = this.createDataSource();               
149
//            }
150
//            
151
//            try {
152
//                conn = this.dataSource.getConnection();
153
//            } catch(Throwable th) {
154
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'. "+this.getStatus());
155
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'.",th);
156
//                throw th;
157
//            }
158
            
159
            
160
            try {
161
                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
162
            } catch(SQLException ex) {
163
                H2GISFunctions.load(conn);
164
            }
165
            try {
166
                conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC");
167
            } catch(SQLException ex) {
168
                LOGGER.trace("Can't create schema public.",ex);
169
                // Ignore this error.
170
            }
171
            
172
            if( newdb ) {
173
                    String[] sqls = new String[] {
174
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\"(\""+FIELD_RESOURCES_NAME+"\" VARCHAR(150) NOT NULL, \""+FIELD_RESOURCES_RESOURCE+"\" BLOB DEFAULT NULL)",
175
                        "ALTER TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_E PRIMARY KEY(\""+FIELD_RESOURCES_NAME+"\")",
176
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\"(\""+FIELD_CONFIGURATION_NAME+"\" VARCHAR(200) NOT NULL, \""+FIELD_CONFIGURATION_VALUE+"\" CLOB DEFAULT NULL)",
177
                        "ALTER TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(\""+FIELD_CONFIGURATION_NAME+"\")"
178
                    };
179
                    for (String sql : sqls) {
180
                        try {
181
                            conn.createStatement().execute(sql);
182
                        } catch(SQLException ex) {
183
                            LOGGER.debug("Can't configure gvsig tables.",ex);
184
                            LOGGER.warn("Can't configure gvsig tables. "+sql);
185
                            // Ignore this error.
186
                        }
187
                    }
188
            }
189
            return conn;
190
        }
191
        
192
        private BasicDataSource createDataSource() throws SQLException {
193
            if (!this.isRegistered()) {
194
                this.registerDriver();
195
            }
196
            H2SpatialConnectionParameters params = connectionParameters;
197

    
198
            BasicDataSource ds = new BasicDataSource();
199
            ds.setDriverClassName(params.getJDBCDriverClassName());
200
            if( !StringUtils.isEmpty(params.getUser()) ) {
201
                ds.setUsername(params.getUser());
202
            }
203
            if( !StringUtils.isEmpty(params.getPassword()) ) {
204
                ds.setPassword(params.getPassword());
205
            }
206
            ds.setUrl(params.getUrl());
207

    
208
            ds.setMaxWait(60L * 1000);
209
            
210
            //
211
            // Ajustamos el pool para que las conexiones se cierren a los
212
            // 10 segundos, asi tratamos de que al salir de gvSIG no queden
213
            // conexiones abiertas con la BBDD y pueda quedar corrupta esta.
214
            // Hay que tener en cuenta que es una BBDD embebida, y mientras
215
            // hayan conexiones abiertas pueden quedar cosas por bajar a disco.
216
            //
217
            int sidle = this.connectionParameters.getMaxSecondsIdle();
218
            if( sidle < 0 ) {
219
                ds.setTimeBetweenEvictionRunsMillis(-1);
220
                ds.setMinEvictableIdleTimeMillis(30*1000);
221
            } else {
222
                // Revisamos las conexiones inactivas cada 10 segundos
223
                ds.setTimeBetweenEvictionRunsMillis(sidle*1000);
224
                // Eliminadmos las conexiones que lleven inactivas mas de 10 segundos.
225
                ds.setMinEvictableIdleTimeMillis(sidle*1000);
226
            }
227
            
228
            // Ajustamos el numero minimo de conexiones a 0 para permitir
229
            // que se lleguen a cerrar todas las conexiones del pool.
230
            ds.setMinIdle(0);
231
            // dejaremos el MaxIdle a 20, no parece importante. .
232
            ds.setMaxIdle(20);
233
            
234
            return ds;
235
        }
236

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

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

    
258
        @Override
259
        public void dispose() {
260
            closeDataSource();
261
            this.connectionParameters = null;
262
        }
263
        
264
        private void closeDataSource() {
265
            try {
266
                if( dataSource!=null ) {
267
                    LOGGER.info("Clossing connection pool.");
268
                    LOGGER.info(this.getStatus());
269
                    dataSource.close();
270
                    dataSource = null;
271
                    LOGGER.info("Connection pool closed.");
272
                    LOGGER.info(this.getStatus());
273
                }
274
            } catch (Throwable th) {
275
                LOGGER.warn("Problems closing connections pool.", th);
276
            }
277

    
278
        }
279

    
280
    }
281

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

    
301
    public void  shutdown() {
302
        try {
303
            if( this.connectionProvider!=null ) {
304
                ((ConnectionProviderImpl) this.connectionProvider).shutdown();
305
                this.connectionProvider = null;
306
            }
307
            H2SpatialUtils.server_stop();
308
        } catch (Throwable ex) {
309
            LOGGER.warn("Problems shutdown H2", ex);
310
        }
311
    }
312

    
313
    private void logConnectionStatus(String msg, Connection conn) {
314
        ConnectionProvider cp = this.getConnectionProvider();
315
        StringBuilder builder = new StringBuilder();
316
        builder.append(msg);
317
        if( conn == null ) {
318
            builder.append(": connection null");
319
        } else {
320
            Boolean closed = null;
321
            try {
322
                closed = conn.isClosed();
323
            } catch(Throwable th) {
324
            }
325
            builder.append(": connection ");
326
            builder.append(JDBCUtils.getConnId(conn));
327
            if( closed ) {
328
                builder.append(" (c)");
329
            }
330
            builder.append(" ");
331
        }
332
        builder.append(cp.getStatus());
333
        LOGGER.info(builder.toString());
334
    }
335
        
336
    private ConnectionProvider getConnectionProvider() {
337
        if (this.connectionProvider == null) {
338
          H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
339
          if( connectionParameters==null ) {
340
            return null; // Testing mode?
341
          }
342
          this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
343
        }
344
        return this.connectionProvider;
345
    }
346
    
347
    @Override
348
    public synchronized Connection  getConnection() throws AccessResourceException {
349
        try {
350
            if (this.connectionProvider == null) {
351
              H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
352
              if( connectionParameters==null ) {
353
                return null; // Testing mode?
354
              }
355
              this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
356
            }
357
            Connection connection = this.connectionProvider.getConnection();
358
            if( LOGGER.isDebugEnabled() ) {
359
                LOGGER.debug("["+JDBCUtils.getConnId(connection)+"] getConnection "+connectionProvider.getStatus()+" "+ connectionProvider.toString());
360
            }
361
            return connection;
362
        } catch (SQLException ex) {
363
            throw new AccessResourceException(H2SpatialLibrary.NAME, ex);
364
        }
365
    }
366

    
367
    @Override
368
    public void closeConnection(Connection connection) {
369
      if( connection!=null ) { // In test ???
370
        LOGGER.debug("["+JDBCUtils.getConnId(connection)+"] closeConnection "+ this.connectionProvider.getStatus());
371
      }
372
      super.closeConnection(connection);
373
    }
374
    
375
    @Override
376
    public H2SpatialConnectionParameters getConnectionParameters() {
377
        return (H2SpatialConnectionParameters) super.getConnectionParameters();
378
    }
379
    
380
    @Override
381
    public String getConnectionURL() {
382
        return H2SpatialUtils.getConnectionURL(this.getConnectionParameters());
383
    }
384

    
385
    @Override
386
    protected String getResourceType() {
387
        return H2SpatialLibrary.NAME;
388
    }
389

    
390
    @Override
391
    public String getProviderName() {
392
        return H2SpatialLibrary.NAME;
393
    }
394

    
395
    @Override
396
    public JDBCSQLBuilderBase createSQLBuilder() {
397
        return new H2SpatialSQLBuilder(this);
398
    }
399
    
400
    @Override
401
    public OperationsFactory getOperations() {
402
        if (this.operationsFactory == null) {
403
            this.operationsFactory = new H2SpatialOperationsFactory(this);
404
        }
405
        return operationsFactory;
406
    }
407

    
408
    @Override
409
    public GeometrySupportType getGeometrySupportType() {
410
        return GeometrySupportType.WKB;
411
    }
412

    
413
    @Override
414
    public boolean hasSpatialFunctions() {
415
        return true;
416
    }
417

    
418
    @Override
419
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
420
        return true;
421
    }
422

    
423
    @Override
424
    public String getQuoteForIdentifiers() {
425
        return "\"";
426
    }
427

    
428
    @Override
429
    public boolean allowAutomaticValues() {
430
        return true;
431
    }
432

    
433
    @Override
434
    public boolean supportOffsetInSelect() {
435
        return true;
436
    }
437

    
438
    @Override
439
    public String getQuoteForStrings() {
440
        return "'";
441
    }
442

    
443
    @Override
444
    public String getSourceId(JDBCStoreParameters parameters) {
445
        H2SpatialStoreParameters h2params = (H2SpatialStoreParameters) parameters;
446
        StringBuilder builder = new StringBuilder();
447
        builder.append(h2params.getTable());
448
        builder.append("(");
449
        if( StringUtils.isNotBlank(h2params.getHost()) ) {
450
            builder.append(h2params.getHost());
451
        }
452
        if( h2params.getPort()>0 ) {
453
            builder.append(",");
454
            builder.append(h2params.getPort());
455
        }
456
        File f = h2params.getFile();       
457
        if( f != null ) {
458
            builder.append(",");
459
            builder.append(h2params.getFile().getAbsolutePath());
460
        }
461
        builder.append(")");
462
        return builder.toString();
463
    }
464

    
465
    @Override
466
    public JDBCNewStoreParameters createNewStoreParameters() {
467
        return new H2SpatialNewStoreParameters();
468
    }
469

    
470
    @Override
471
    public JDBCStoreParameters createOpenStoreParameters() {
472
        return new H2SpatialStoreParameters();
473
    }
474

    
475
    @Override
476
    public JDBCServerExplorerParameters createServerExplorerParameters() {
477
        return new H2SpatialExplorerParameters();
478
    }
479

    
480
    @Override
481
    public JDBCServerExplorer createServerExplorer(
482
            JDBCServerExplorerParameters parameters, 
483
            DataServerExplorerProviderServices providerServices
484
        ) throws InitializeException {
485
        
486
        JDBCServerExplorer explorer = new H2SpatialExplorer(
487
                parameters, 
488
                providerServices, 
489
                this
490
        );
491
        this.initialize(explorer, parameters, null);
492
        return explorer;
493
    }
494
    
495
    public String getConnectionProviderStatus(){
496
        return this.getConnectionProvider().getStatus();
497
    }
498
}