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

History | View | Annotate | Download (18.8 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.functions.Json_value;
42
import org.gvsig.fmap.dal.store.h2.functions.Reverse;
43
import org.gvsig.fmap.dal.store.h2.functions.Reverseinstr;
44
import org.gvsig.fmap.dal.store.h2.operations.H2SpatialOperationsFactory;
45
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
46
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
47
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
48
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
49
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
50
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
51
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
52
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
55
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
56
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
57
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
58
import org.h2.tools.Server;
59
import org.h2gis.functions.factory.H2GISFunctions;
60
import org.h2gis.functions.system.H2GISversion;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64

    
65
@SuppressWarnings("UseSpecificCatch")
66
public class H2SpatialHelper extends JDBCHelperBase {
67

    
68
    static final Logger LOGGER = LoggerFactory.getLogger(H2SpatialHelper.class);
69

    
70
    public static final String H2SPATIAL_JDBC_DRIVER = "org.h2.Driver";
71
    
72
    public static class ConnectionProviderImpl implements ConnectionProvider {
73

    
74
        private static boolean needRegisterDriver = true;
75

    
76
        private BasicDataSource dataSource = null;
77

    
78
        private H2SpatialConnectionParameters connectionParameters;
79
        
80
        public ConnectionProviderImpl(H2SpatialConnectionParameters connectionParameters) {
81
            this.connectionParameters = connectionParameters;
82
        }
83

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

    
141
            } catch(Throwable th) {
142
                throw th;
143
            }
144
            
145
            H2SpatialUtils.server_start(
146
                    this.connectionParameters.getServerPortAsString(), 
147
                    this.connectionParameters.getServerAllowOthers()
148
            );
149
            
150
//            if (this.dataSource == null) {
151
//                this.dataSource = this.createDataSource();               
152
//            }
153
//            
154
//            try {
155
//                conn = this.dataSource.getConnection();
156
//            } catch(Throwable th) {
157
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'. "+this.getStatus());
158
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'.",th);
159
//                throw th;
160
//            }
161
            
162
            
163
            try {
164
                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
165
            } catch(SQLException ex) {
166
                H2GISFunctions.load(conn);
167
            }
168

    
169
            String[] sqls = new String[] {
170
                "CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC",
171
                        Json_value.getSQL(),
172
                        Reverse.getSQL(),
173
                        Reverseinstr.getSQL()
174
            };
175
            for (String sql : sqls) {
176
                try {
177
                    conn.createStatement().execute(sql);
178
                } catch(SQLException ex) {
179
                    LOGGER.debug("Can't configure gvsig tables.",ex);
180
                    LOGGER.warn("Can't configure gvsig tables. "+sql);
181
                    // Ignore this error.
182
                }
183
            }
184
            
185
            if( newdb ) {
186
                    String[] sqls2 = new String[] {
187
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\"(\""+FIELD_RESOURCES_NAME+"\" VARCHAR(150) NOT NULL, \""+FIELD_RESOURCES_RESOURCE+"\" BLOB DEFAULT NULL)",
188
                        "ALTER TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_E PRIMARY KEY(\""+FIELD_RESOURCES_NAME+"\")",
189
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\"(\""+FIELD_CONFIGURATION_NAME+"\" VARCHAR(200) NOT NULL, \""+FIELD_CONFIGURATION_VALUE+"\" CLOB DEFAULT NULL)",
190
                        "ALTER TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(\""+FIELD_CONFIGURATION_NAME+"\")",
191
                    };
192
                    for (String sql : sqls2) {
193
                        try {
194
                            conn.createStatement().execute(sql);
195
                        } catch(SQLException ex) {
196
                            LOGGER.debug("Can't configure gvsig tables.",ex);
197
                            LOGGER.warn("Can't configure gvsig tables. "+sql);
198
                            // Ignore this error.
199
                        }
200
                    }
201
            }
202
            return conn;
203
        }
204
        
205
        private BasicDataSource createDataSource() throws SQLException {
206
            if (!this.isRegistered()) {
207
                this.registerDriver();
208
            }
209
            H2SpatialConnectionParameters params = connectionParameters;
210

    
211
            BasicDataSource ds = new BasicDataSource();
212
            ds.setDriverClassName(params.getJDBCDriverClassName());
213
            if( !StringUtils.isEmpty(params.getUser()) ) {
214
                ds.setUsername(params.getUser());
215
            }
216
            if( !StringUtils.isEmpty(params.getPassword()) ) {
217
                ds.setPassword(params.getPassword());
218
            }
219
            ds.setUrl(params.getUrl());
220

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

    
250
        private boolean isRegistered() {
251
            return needRegisterDriver;
252
        }
253

    
254
        @Override
255
        public void registerDriver() throws SQLException {
256
            String className = this.connectionParameters.getJDBCDriverClassName();
257
            if (className == null) {
258
                return;
259
            }
260
            try {
261
                Class theClass = Class.forName(className);
262
                if (theClass == null) {
263
                    throw new JDBCDriverClassNotFoundException(H2SpatialLibrary.NAME, className);
264
                }
265
            } catch (Exception e) {
266
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
267
            }
268
            needRegisterDriver = false;
269
        }
270

    
271
        @Override
272
        public void dispose() {
273
            closeDataSource();
274
            this.connectionParameters = null;
275
        }
276
        
277
        private void closeDataSource() {
278
            try {
279
                if( dataSource!=null ) {
280
                    LOGGER.info("Clossing connection pool.");
281
                    LOGGER.info(this.getStatus());
282
                    dataSource.close();
283
                    dataSource = null;
284
                    LOGGER.info("Connection pool closed.");
285
                    LOGGER.info(this.getStatus());
286
                }
287
            } catch (Throwable th) {
288
                LOGGER.warn("Problems closing connections pool.", th);
289
            }
290

    
291
        }
292

    
293
    }
294

    
295
    private ConnectionProvider connectionProvider = null;
296
 
297
    /**
298
     * Constructor for use only for testing purposes.
299
     * 
300
     * @param connectionParameters
301
     * @param connectionProvider
302
     */
303
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters, ConnectionProvider connectionProvider) { 
304
        super(connectionParameters);
305
        this.srssolver = new SRSSolverDumb(this);
306
        this.connectionProvider = connectionProvider;
307
    }
308
  
309
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters) {
310
        super(connectionParameters);
311
        this.srssolver = new SRSSolverBase(this);
312
    }
313

    
314
    public void  shutdown() {
315
        try {
316
            if( this.connectionProvider!=null ) {
317
                ((ConnectionProviderImpl) this.connectionProvider).shutdown();
318
                this.connectionProvider = null;
319
            }
320
            H2SpatialUtils.server_stop();
321
        } catch (Throwable ex) {
322
            LOGGER.warn("Problems shutdown H2", ex);
323
        }
324
    }
325

    
326
    private void logConnectionStatus(String msg, Connection conn) {
327
        ConnectionProvider cp = this.getConnectionProvider();
328
        StringBuilder builder = new StringBuilder();
329
        builder.append(msg);
330
        if( conn == null ) {
331
            builder.append(": connection null");
332
        } else {
333
            Boolean closed = null;
334
            try {
335
                closed = conn.isClosed();
336
            } catch(Throwable th) {
337
            }
338
            builder.append(": connection ");
339
            builder.append(JDBCUtils.getConnId(conn));
340
            if( closed ) {
341
                builder.append(" (c)");
342
            }
343
            builder.append(" ");
344
        }
345
        builder.append(cp.getStatus());
346
        LOGGER.info(builder.toString());
347
    }
348
        
349
    private ConnectionProvider getConnectionProvider() {
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
        return this.connectionProvider;
358
    }
359
    
360
    @Override
361
    public synchronized Connection  getConnection() throws AccessResourceException {
362
        try {
363
            if (this.connectionProvider == null) {
364
              H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
365
              if( connectionParameters==null ) {
366
                return null; // Testing mode?
367
              }
368
              this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
369
            }
370
            Connection connection = this.connectionProvider.getConnection();
371
            if( LOGGER.isDebugEnabled() ) {
372
                LOGGER.debug("["+JDBCUtils.getConnId(connection)+"] getConnection "+connectionProvider.getStatus()+" "+ connectionProvider.toString());
373
            }
374
            return connection;
375
        } catch (SQLException ex) {
376
            throw new AccessResourceException(H2SpatialLibrary.NAME, ex);
377
        }
378
    }
379

    
380
    @Override
381
    public void closeConnection(Connection connection) {
382
      if( connection!=null ) { // In test ???
383
        LOGGER.debug("["+JDBCUtils.getConnId(connection)+"] closeConnection "+ this.connectionProvider.getStatus());
384
      }
385
      super.closeConnection(connection);
386
    }
387
    
388
    @Override
389
    public H2SpatialConnectionParameters getConnectionParameters() {
390
        return (H2SpatialConnectionParameters) super.getConnectionParameters();
391
    }
392
    
393
    @Override
394
    public String getConnectionURL() {
395
        return H2SpatialUtils.getConnectionURL(this.getConnectionParameters());
396
    }
397

    
398
    @Override
399
    protected String getResourceType() {
400
        return H2SpatialLibrary.NAME;
401
    }
402

    
403
    @Override
404
    public String getProviderName() {
405
        return H2SpatialLibrary.NAME;
406
    }
407

    
408
    @Override
409
    public JDBCSQLBuilderBase createSQLBuilder() {
410
        return new H2SpatialSQLBuilder(this);
411
    }
412
    
413
    @Override
414
    public OperationsFactory getOperations() {
415
        if (this.operationsFactory == null) {
416
            this.operationsFactory = new H2SpatialOperationsFactory(this);
417
        }
418
        return operationsFactory;
419
    }
420

    
421
    @Override
422
    public GeometrySupportType getGeometrySupportType() {
423
        return GeometrySupportType.WKB;
424
    }
425

    
426
    @Override
427
    public boolean hasSpatialFunctions() {
428
        return true;
429
    }
430

    
431
    @Override
432
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
433
        return true;
434
    }
435

    
436
    @Override
437
    public String getQuoteForIdentifiers() {
438
        return "\"";
439
    }
440

    
441
    @Override
442
    public boolean allowAutomaticValues() {
443
        return true;
444
    }
445

    
446
    @Override
447
    public boolean supportOffsetInSelect() {
448
        return true;
449
    }
450

    
451
    @Override
452
    public String getQuoteForStrings() {
453
        return "'";
454
    }
455

    
456
    @Override
457
    public String getSourceId(JDBCStoreParameters parameters) {
458
        H2SpatialStoreParameters h2params = (H2SpatialStoreParameters) parameters;
459
        StringBuilder builder = new StringBuilder();
460
        builder.append(h2params.getTable());
461
        builder.append("(");
462
        if( StringUtils.isNotBlank(h2params.getHost()) ) {
463
            builder.append(h2params.getHost());
464
        }
465
        if( h2params.getPort()>0 ) {
466
            builder.append(",");
467
            builder.append(h2params.getPort());
468
        }
469
        File f = h2params.getFile();       
470
        if( f != null ) {
471
            builder.append(",");
472
            builder.append(h2params.getFile().getAbsolutePath());
473
        }
474
        builder.append(")");
475
        return builder.toString();
476
    }
477

    
478
    @Override
479
    public JDBCNewStoreParameters createNewStoreParameters() {
480
        return new H2SpatialNewStoreParameters();
481
    }
482

    
483
    @Override
484
    public JDBCStoreParameters createOpenStoreParameters() {
485
        return new H2SpatialStoreParameters();
486
    }
487

    
488
    @Override
489
    public JDBCServerExplorerParameters createServerExplorerParameters() {
490
        return new H2SpatialExplorerParameters();
491
    }
492

    
493
    @Override
494
    public JDBCServerExplorer createServerExplorer(
495
            JDBCServerExplorerParameters parameters, 
496
            DataServerExplorerProviderServices providerServices
497
        ) throws InitializeException {
498
        
499
        JDBCServerExplorer explorer = new H2SpatialExplorer(
500
                parameters, 
501
                providerServices, 
502
                this
503
        );
504
        this.initialize(explorer, parameters, null);
505
        return explorer;
506
    }
507
    
508
    public String getConnectionProviderStatus(){
509
        return this.getConnectionProvider().getStatus();
510
    }
511
}