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

History | View | Annotate | Download (20 KB)

1 45472 jjdelcerro
/* 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 45742 fdiaz
import java.sql.DriverManager;
27 45472 jjdelcerro
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 45488 fdiaz
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 45472 jjdelcerro
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 46315 jjdelcerro
import org.gvsig.fmap.dal.spi.DataTransactionServices;
41 45472 jjdelcerro
import static org.gvsig.fmap.dal.store.h2.H2SpatialHelper.LOGGER;
42 46047 jjdelcerro
import org.gvsig.fmap.dal.store.h2.functions.Json_value;
43
import org.gvsig.fmap.dal.store.h2.functions.Reverse;
44
import org.gvsig.fmap.dal.store.h2.functions.Reverseinstr;
45 45472 jjdelcerro
import org.gvsig.fmap.dal.store.h2.operations.H2SpatialOperationsFactory;
46
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
47
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
48
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
49
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
50
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
51 46315 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
52 45472 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
53
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
54
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
55 46361 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.spi.AbstractConnectionProvider;
56 45488 fdiaz
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
57 46315 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCConnectionBase;
58 45472 jjdelcerro
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
59
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
60
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverBase;
61
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
62 45488 fdiaz
import org.h2gis.functions.factory.H2GISFunctions;
63 45472 jjdelcerro
import org.slf4j.Logger;
64
import org.slf4j.LoggerFactory;
65
66
67
@SuppressWarnings("UseSpecificCatch")
68
public class H2SpatialHelper extends JDBCHelperBase {
69
70
    static final Logger LOGGER = LoggerFactory.getLogger(H2SpatialHelper.class);
71
72
    public static final String H2SPATIAL_JDBC_DRIVER = "org.h2.Driver";
73
74 46361 jjdelcerro
    public static class ConnectionProviderImpl extends AbstractConnectionProvider implements ConnectionProvider {
75 45472 jjdelcerro
76
        private static boolean needRegisterDriver = true;
77
78
        private BasicDataSource dataSource = null;
79
80 45694 fdiaz
        private H2SpatialConnectionParameters connectionParameters;
81 45472 jjdelcerro
82
        public ConnectionProviderImpl(H2SpatialConnectionParameters connectionParameters) {
83
            this.connectionParameters = connectionParameters;
84
        }
85
86
        @Override
87
        public String getStatus() {
88 45742 fdiaz
            if(dataSource == null) {
89
                return "Not using pool.";
90
            }
91 45472 jjdelcerro
            StringBuilder builder = new StringBuilder();
92
            builder.append("Pool: ");
93
            builder.append(JDBCUtils.getHexId(dataSource));
94
            builder.append(" Actives: ");
95
            builder.append(dataSource.getNumActive());
96
            builder.append("/");
97
            builder.append(dataSource.getMaxActive());
98
            builder.append(" idle: ");
99
            builder.append(dataSource.getNumIdle());
100
            builder.append("/");
101
            builder.append(dataSource.getMinIdle());
102
            builder.append(":");
103
            builder.append(dataSource.getMaxIdle());
104
            return builder.toString();
105
        }
106
107
        @SuppressWarnings("ConvertToTryWithResources")
108
        public void shutdown() {
109
            LOGGER.info("Shutdown H2 connection.");
110
            try {
111
                Connection conn = this.getConnection();
112 46200 jjdelcerro
                conn.createStatement().execute("CHECKPOINT SYNC");
113 46230 jjdelcerro
                conn.createStatement().execute("ANALYZE");
114
                conn.createStatement().execute("SHUTDOWN COMPACT");
115 45472 jjdelcerro
                conn.close();
116 46230 jjdelcerro
                LOGGER.info("Shutdown completed.");
117 45472 jjdelcerro
            } catch (Throwable th) {
118
                LOGGER.warn("Problems shutdown the database.", th);
119
            }
120 45742 fdiaz
            closeDataSource();
121 45472 jjdelcerro
        }
122
123
        @Override
124
        public String toString() {
125
            StringBuilder builder = new StringBuilder();
126
            builder.append(" url=").append(connectionParameters.getUrl());
127
            builder.append(" driver name=").append(connectionParameters.getJDBCDriverClassName());
128
            builder.append(" user=").append(connectionParameters.getUser());
129
            return builder.toString();
130
        }
131
132
        @Override
133
        public synchronized Connection getConnection() throws SQLException {
134 45901 jjdelcerro
            File f = H2SpatialUtils.getLocalFile(connectionParameters);
135 46252 jjdelcerro
            boolean newdb = f!=null && !f.exists();
136 45472 jjdelcerro
137
            Connection conn;
138 45742 fdiaz
139 45472 jjdelcerro
            try {
140 45742 fdiaz
                conn = DriverManager.getConnection(
141
                    connectionParameters.getUrl(),
142
                    connectionParameters.getUser(),
143
                    connectionParameters.getPassword()
144
                );
145
146 45472 jjdelcerro
            } catch(Throwable th) {
147
                throw th;
148
            }
149 45742 fdiaz
150 45901 jjdelcerro
            H2SpatialUtils.server_start(
151
                    this.connectionParameters.getServerPortAsString(),
152
                    this.connectionParameters.getServerAllowOthers()
153
            );
154 45742 fdiaz
155
//            if (this.dataSource == null) {
156
//                this.dataSource = this.createDataSource();
157
//            }
158
//
159
//            try {
160
//                conn = this.dataSource.getConnection();
161
//            } catch(Throwable th) {
162
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'. "+this.getStatus());
163
//                LOGGER.warn("Can't create connection to '"+this.dataSource.getUrl()+"'.",th);
164
//                throw th;
165
//            }
166
167
168 45472 jjdelcerro
            try {
169
                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
170
            } catch(SQLException ex) {
171
                H2GISFunctions.load(conn);
172
            }
173 46047 jjdelcerro
174
            String[] sqls = new String[] {
175
                "CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC",
176 46050 omartinez
                        Json_value.getSQL(),
177
                        Reverse.getSQL(),
178
                        Reverseinstr.getSQL()
179 46047 jjdelcerro
            };
180
            for (String sql : sqls) {
181
                try {
182
                    conn.createStatement().execute(sql);
183
                } catch(SQLException ex) {
184
                    LOGGER.debug("Can't configure gvsig tables.",ex);
185
                    LOGGER.warn("Can't configure gvsig tables. "+sql);
186
                    // Ignore this error.
187
                }
188 45472 jjdelcerro
            }
189 45488 fdiaz
190 45472 jjdelcerro
            if( newdb ) {
191 46047 jjdelcerro
                    String[] sqls2 = new String[] {
192 45488 fdiaz
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\"(\""+FIELD_RESOURCES_NAME+"\" VARCHAR(150) NOT NULL, \""+FIELD_RESOURCES_RESOURCE+"\" BLOB DEFAULT NULL)",
193
                        "ALTER TABLE PUBLIC.\""+TABLE_RESOURCES_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_E PRIMARY KEY(\""+FIELD_RESOURCES_NAME+"\")",
194 45767 fdiaz
                        "CREATE CACHED TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\"(\""+FIELD_CONFIGURATION_NAME+"\" VARCHAR(200) NOT NULL, \""+FIELD_CONFIGURATION_VALUE+"\" CLOB DEFAULT NULL)",
195 46047 jjdelcerro
                        "ALTER TABLE PUBLIC.\""+TABLE_CONFIGURATION_NAME+"\" ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(\""+FIELD_CONFIGURATION_NAME+"\")",
196 45472 jjdelcerro
                    };
197 46047 jjdelcerro
                    for (String sql : sqls2) {
198 45472 jjdelcerro
                        try {
199
                            conn.createStatement().execute(sql);
200
                        } catch(SQLException ex) {
201
                            LOGGER.debug("Can't configure gvsig tables.",ex);
202
                            LOGGER.warn("Can't configure gvsig tables. "+sql);
203
                            // Ignore this error.
204
                        }
205
                    }
206
            }
207
            return conn;
208
        }
209
210
        private BasicDataSource createDataSource() throws SQLException {
211
            if (!this.isRegistered()) {
212
                this.registerDriver();
213
            }
214
            H2SpatialConnectionParameters params = connectionParameters;
215
216
            BasicDataSource ds = new BasicDataSource();
217
            ds.setDriverClassName(params.getJDBCDriverClassName());
218
            if( !StringUtils.isEmpty(params.getUser()) ) {
219
                ds.setUsername(params.getUser());
220
            }
221
            if( !StringUtils.isEmpty(params.getPassword()) ) {
222
                ds.setPassword(params.getPassword());
223
            }
224
            ds.setUrl(params.getUrl());
225
226
            ds.setMaxWait(60L * 1000);
227
228
            //
229
            // Ajustamos el pool para que las conexiones se cierren a los
230
            // 10 segundos, asi tratamos de que al salir de gvSIG no queden
231
            // conexiones abiertas con la BBDD y pueda quedar corrupta esta.
232
            // Hay que tener en cuenta que es una BBDD embebida, y mientras
233
            // hayan conexiones abiertas pueden quedar cosas por bajar a disco.
234
            //
235
            int sidle = this.connectionParameters.getMaxSecondsIdle();
236
            if( sidle < 0 ) {
237
                ds.setTimeBetweenEvictionRunsMillis(-1);
238
                ds.setMinEvictableIdleTimeMillis(30*1000);
239
            } else {
240
                // Revisamos las conexiones inactivas cada 10 segundos
241
                ds.setTimeBetweenEvictionRunsMillis(sidle*1000);
242
                // Eliminadmos las conexiones que lleven inactivas mas de 10 segundos.
243
                ds.setMinEvictableIdleTimeMillis(sidle*1000);
244
            }
245
246
            // Ajustamos el numero minimo de conexiones a 0 para permitir
247
            // que se lleguen a cerrar todas las conexiones del pool.
248
            ds.setMinIdle(0);
249
            // dejaremos el MaxIdle a 20, no parece importante. .
250
            ds.setMaxIdle(20);
251
252
            return ds;
253
        }
254
255
        private boolean isRegistered() {
256
            return needRegisterDriver;
257
        }
258
259
        @Override
260
        public void registerDriver() throws SQLException {
261
            String className = this.connectionParameters.getJDBCDriverClassName();
262
            if (className == null) {
263
                return;
264
            }
265
            try {
266
                Class theClass = Class.forName(className);
267
                if (theClass == null) {
268
                    throw new JDBCDriverClassNotFoundException(H2SpatialLibrary.NAME, className);
269
                }
270
            } catch (Exception e) {
271
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
272
            }
273
            needRegisterDriver = false;
274
        }
275
276 45694 fdiaz
        @Override
277
        public void dispose() {
278 45742 fdiaz
            closeDataSource();
279
            this.connectionParameters = null;
280
        }
281
282
        private void closeDataSource() {
283
            try {
284
                if( dataSource!=null ) {
285
                    LOGGER.info("Clossing connection pool.");
286
                    LOGGER.info(this.getStatus());
287
                    dataSource.close();
288
                    dataSource = null;
289
                    LOGGER.info("Connection pool closed.");
290
                    LOGGER.info(this.getStatus());
291 45694 fdiaz
                }
292 45742 fdiaz
            } catch (Throwable th) {
293
                LOGGER.warn("Problems closing connections pool.", th);
294 45694 fdiaz
            }
295 45742 fdiaz
296 45694 fdiaz
        }
297
298 46361 jjdelcerro
        @Override
299
        public boolean isDisposed() {
300
            return this.connectionParameters == null;
301
        }
302 45472 jjdelcerro
    }
303
304
    private ConnectionProvider connectionProvider = null;
305
306
    /**
307
     * Constructor for use only for testing purposes.
308
     *
309
     * @param connectionParameters
310
     * @param connectionProvider
311
     */
312
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters, ConnectionProvider connectionProvider) {
313
        super(connectionParameters);
314
        this.srssolver = new SRSSolverDumb(this);
315
        this.connectionProvider = connectionProvider;
316
    }
317
318
    public H2SpatialHelper(JDBCConnectionParameters connectionParameters) {
319
        super(connectionParameters);
320 46354 jjdelcerro
//        this.srssolver = new SRSSolverBase(this);
321
        this.srssolver = new SRSSolverDumb(this); //Tratando de reducir accesos a la BBDD ? Ponerlo en los parametros ?
322 45472 jjdelcerro
    }
323
324
    public void  shutdown() {
325
        try {
326 46230 jjdelcerro
            try {
327
                this.getConnection();
328
            } catch(Throwable th) {
329
                LOGGER.debug("Can't get connection-provider",th);
330
            }
331 45472 jjdelcerro
            if( this.connectionProvider!=null ) {
332
                ((ConnectionProviderImpl) this.connectionProvider).shutdown();
333
                this.connectionProvider = null;
334
            }
335 45901 jjdelcerro
            H2SpatialUtils.server_stop();
336 45472 jjdelcerro
        } catch (Throwable ex) {
337
            LOGGER.warn("Problems shutdown H2", ex);
338
        }
339
    }
340
341
    private void logConnectionStatus(String msg, Connection conn) {
342
        ConnectionProvider cp = this.getConnectionProvider();
343
        StringBuilder builder = new StringBuilder();
344
        builder.append(msg);
345
        if( conn == null ) {
346
            builder.append(": connection null");
347
        } else {
348
            Boolean closed = null;
349
            try {
350
                closed = conn.isClosed();
351
            } catch(Throwable th) {
352
            }
353
            builder.append(": connection ");
354
            builder.append(JDBCUtils.getConnId(conn));
355
            if( closed ) {
356
                builder.append(" (c)");
357
            }
358
            builder.append(" ");
359
        }
360
        builder.append(cp.getStatus());
361
        LOGGER.info(builder.toString());
362
    }
363
364 46361 jjdelcerro
    public ConnectionProvider getConnectionProvider() {
365 45472 jjdelcerro
        if (this.connectionProvider == null) {
366
          H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
367
          if( connectionParameters==null ) {
368
            return null; // Testing mode?
369
          }
370
          this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
371
        }
372
        return this.connectionProvider;
373
    }
374
375
    @Override
376 46315 jjdelcerro
    public synchronized JDBCConnection  getConnection() throws AccessResourceException {
377 45472 jjdelcerro
        try {
378 46315 jjdelcerro
            H2SpatialConnectionParameters connectionParameters = this.getConnectionParameters();
379
            JDBCConnection conn = (JDBCConnection) DataTransactionServices.getConnection(transaction, connectionParameters.getUrl());
380
            if( conn != null ) {
381
                return conn;
382
            }
383 45472 jjdelcerro
            if (this.connectionProvider == null) {
384
              if( connectionParameters==null ) {
385
                return null; // Testing mode?
386
              }
387
              this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
388
            }
389 46315 jjdelcerro
            JDBCConnection connection = new JDBCConnectionBase(
390
                    this.transaction,
391
                    this.connectionProvider.getConnection(),
392
                    connectionParameters.getUrl()
393
            );
394 45472 jjdelcerro
            if( LOGGER.isDebugEnabled() ) {
395 46315 jjdelcerro
                LOGGER.debug("["+JDBCUtils.getConnId(connection.get())+"] getConnection "+connectionProvider.getStatus()+" "+ connectionProvider.toString());
396 45472 jjdelcerro
            }
397
            return connection;
398
        } catch (SQLException ex) {
399
            throw new AccessResourceException(H2SpatialLibrary.NAME, ex);
400
        }
401
    }
402
403
    @Override
404
    public H2SpatialConnectionParameters getConnectionParameters() {
405
        return (H2SpatialConnectionParameters) super.getConnectionParameters();
406
    }
407
408
    @Override
409
    public String getConnectionURL() {
410 45901 jjdelcerro
        return H2SpatialUtils.getConnectionURL(this.getConnectionParameters());
411 45472 jjdelcerro
    }
412
413
    @Override
414
    protected String getResourceType() {
415
        return H2SpatialLibrary.NAME;
416
    }
417
418
    @Override
419
    public String getProviderName() {
420
        return H2SpatialLibrary.NAME;
421
    }
422
423
    @Override
424
    public JDBCSQLBuilderBase createSQLBuilder() {
425
        return new H2SpatialSQLBuilder(this);
426
    }
427
428
    @Override
429
    public OperationsFactory getOperations() {
430
        if (this.operationsFactory == null) {
431
            this.operationsFactory = new H2SpatialOperationsFactory(this);
432
        }
433
        return operationsFactory;
434
    }
435
436
    @Override
437
    public GeometrySupportType getGeometrySupportType() {
438
        return GeometrySupportType.WKB;
439
    }
440
441
    @Override
442
    public boolean hasSpatialFunctions() {
443
        return true;
444
    }
445
446
    @Override
447
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
448
        return true;
449
    }
450
451
    @Override
452
    public String getQuoteForIdentifiers() {
453
        return "\"";
454
    }
455
456
    @Override
457
    public boolean allowAutomaticValues() {
458
        return true;
459
    }
460
461
    @Override
462
    public boolean supportOffsetInSelect() {
463
        return true;
464
    }
465
466
    @Override
467
    public String getQuoteForStrings() {
468
        return "'";
469
    }
470
471
    @Override
472
    public String getSourceId(JDBCStoreParameters parameters) {
473 45499 jjdelcerro
        H2SpatialStoreParameters h2params = (H2SpatialStoreParameters) parameters;
474
        StringBuilder builder = new StringBuilder();
475
        builder.append(h2params.getTable());
476
        builder.append("(");
477
        if( StringUtils.isNotBlank(h2params.getHost()) ) {
478
            builder.append(h2params.getHost());
479
        }
480
        if( h2params.getPort()>0 ) {
481
            builder.append(",");
482
            builder.append(h2params.getPort());
483
        }
484
        File f = h2params.getFile();
485
        if( f != null ) {
486
            builder.append(",");
487
            builder.append(h2params.getFile().getAbsolutePath());
488
        }
489
        builder.append(")");
490
        return builder.toString();
491 45472 jjdelcerro
    }
492
493
    @Override
494
    public JDBCNewStoreParameters createNewStoreParameters() {
495
        return new H2SpatialNewStoreParameters();
496
    }
497
498
    @Override
499
    public JDBCStoreParameters createOpenStoreParameters() {
500
        return new H2SpatialStoreParameters();
501
    }
502
503
    @Override
504
    public JDBCServerExplorerParameters createServerExplorerParameters() {
505
        return new H2SpatialExplorerParameters();
506
    }
507
508
    @Override
509
    public JDBCServerExplorer createServerExplorer(
510
            JDBCServerExplorerParameters parameters,
511
            DataServerExplorerProviderServices providerServices
512
        ) throws InitializeException {
513
514
        JDBCServerExplorer explorer = new H2SpatialExplorer(
515
                parameters,
516
                providerServices,
517
                this
518
        );
519
        this.initialize(explorer, parameters, null);
520
        return explorer;
521
    }
522
523 45742 fdiaz
    public String getConnectionProviderStatus(){
524
        return this.getConnectionProvider().getStatus();
525
    }
526 46338 fdiaz
527
    @Override
528
    public JDBCStoreParameters createOpenStoreParameters(JDBCServerExplorerParameters parameters) {
529
        JDBCStoreParameters p = super.createOpenStoreParameters(parameters);
530
        if(StringUtils.isBlank(p.getCatalog())){
531
            p.setCatalog(StringUtils.upperCase(p.getDBName()));
532
        }
533
        return p;
534
    }
535
536
537 45472 jjdelcerro
}