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.mdb / src / main / java / org / gvsig / fmap / dal / store / mdb / MDBHelper.java @ 46315

History | View | Annotate | Download (16.8 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.mdb;
23

    
24
import java.io.File;
25
import java.io.IOException;
26
import java.sql.Clob;
27
import java.sql.Connection;
28
import java.sql.ResultSet;
29
import java.sql.SQLException;
30
import java.text.MessageFormat;
31
import org.apache.commons.dbcp.BasicDataSource;
32
import org.apache.commons.io.IOUtils;
33
import org.apache.commons.lang3.StringUtils;
34
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
35
import org.gvsig.fmap.dal.exception.DataException;
36
import org.gvsig.fmap.dal.exception.InitializeException;
37
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
38
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
39
import org.gvsig.fmap.dal.spi.DataTransactionServices;
40
import org.gvsig.fmap.dal.store.mdb.operations.MDBOperationsFactory;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
42
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
43
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
44
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
45
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
46
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
47
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
48
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
49
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
50
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCConnectionBase;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
55
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCServerExplorerBase;
56
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
57
import org.gvsig.fmap.geom.Geometry;
58
//import org.h2.tools.Server;
59
//import org.h2gis.ext.H2GISExtension;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62

    
63
@SuppressWarnings("UseSpecificCatch")
64
public class MDBHelper extends JDBCHelperBase {
65

    
66
    static final Logger LOGGER = LoggerFactory.getLogger(MDBHelper.class);
67

    
68
    public static final String MDB_JDBC_DRIVER = "net.ucanaccess.jdbc.UcanaccessDriver";
69

    
70
    public static String getConnectionURL(MDBConnectionParameters params) {
71
        String connectionURL;
72
        String dbfilename = params.getFile().getAbsolutePath().replace("\\","/");
73
//        if( dbfilename!=null && dbfilename.endsWith(".mdb") ) {
74
//            dbfilename = dbfilename.substring(0, dbfilename.length()-3);
75
//        }
76
        StringBuilder commonParameters = new StringBuilder();
77
//        commonParameters.append(";MODE=PostgreSQL");
78
//        commonParameters.append(";SCHEMA=PUBLIC");
79
        
80
//        Integer LOCK_TIMEOUT = (Integer) params.getDynValue("LOCK_TIMEOUT");
81
//        if( LOCK_TIMEOUT!=null ) {
82
//            commonParameters.append(";LOCK_TIMEOUT=").append(LOCK_TIMEOUT);
83
//        }
84
//        Integer MULTI_THREADED = (Integer) params.getDynValue("MULTI_THREADED");
85
//        if( MULTI_THREADED!=null ) {
86
//            commonParameters.append(";MULTI_THREADED=").append(MULTI_THREADED);
87
//        }
88
//        Integer CHACHE_SIZE = (Integer) params.getDynValue("CHACHE_SIZE");
89
//        if( LOCK_TIMEOUT!=null ) {
90
//            commonParameters.append(";CHACHE_SIZE=").append(CHACHE_SIZE);
91
//        }
92
//        Integer LOG = (Integer) params.getDynValue("LOG");
93
//        if( LOCK_TIMEOUT!=null ) {
94
//            commonParameters.append(";LOG=").append(LOG);
95
//        }
96
//        Integer LOCK_MODE = (Integer) params.getDynValue("LOCK_MODE");
97
//        if( LOCK_TIMEOUT!=null ) {
98
//            commonParameters.append(";LOCK_MODE=").append(LOCK_MODE);
99
//        }
100
        if (!params.getFile().exists()) {
101
            commonParameters.append("newdatabaseversion=V2010;");
102
        }
103
        commonParameters.append("showSchema=true;");
104
        
105
        // http://ucanaccess.sourceforge.net/site.html#examples
106
        connectionURL =  MessageFormat.format(                
107
                "jdbc:ucanaccess://{0};"+commonParameters.toString(),
108
                dbfilename
109
        );
110
        
111
        LOGGER.debug("connectionURL: {}", connectionURL);
112
        return connectionURL;
113
    }
114

    
115
    public static class ConnectionProviderImpl implements ConnectionProvider {
116

    
117
        private static boolean needRegisterDriver = true;
118

    
119
        private BasicDataSource dataSource = null;
120

    
121
        private MDBConnectionParameters connectionParameters;
122

    
123
//        private static Server server = null;
124
        private static String server = null;
125
        private static boolean startServer = true;
126

    
127
        public ConnectionProviderImpl(MDBConnectionParameters connectionParameters) {
128
            this.connectionParameters = connectionParameters;
129
        }
130
        
131
        @Override
132
        public String getStatus() {
133
            StringBuilder builder = new StringBuilder();
134
            builder.append("Pool: ");
135
            builder.append(JDBCUtils.getHexId(dataSource));
136
            builder.append(" Actives: ");
137
            builder.append(dataSource.getNumActive());
138
            builder.append("/");
139
            builder.append(dataSource.getMaxActive());
140
            builder.append(" idle: ");
141
            builder.append(dataSource.getNumIdle());
142
            builder.append("/");
143
            builder.append(dataSource.getMinIdle());
144
            builder.append(":");
145
            builder.append(dataSource.getMaxIdle());
146
            return builder.toString();
147
        }
148

    
149
        
150
        public static void stopServer() {
151
          try {
152
//            server.shutdown();
153
          } catch(Throwable th) {
154
            
155
          }
156
          try {
157
//            server.stop();
158
          } catch(Throwable th) {
159
            
160
          }
161
//          server = null;
162
          startServer = true;
163
          LOGGER.info("MDB Server stopped" );
164
        }
165
        
166
        private void startServer() {
167
        
168
            if( startServer && server == null ) {
169
                String port = "9123";
170
//                Server theServer;
171
                String s = System.getProperty("MDBPort");
172
                if( s!=null ) {
173
                    try {
174
                        int n = Integer.parseInt(s);
175
                        port = String.valueOf(n);
176
                    } catch(Throwable th) {
177
                        // Ignore port number, use default.
178
                    }
179
                }
180
                if( System.getProperty("MDBAllowOthers")!=null ) {
181
//                    theServer = Server.createTcpServer("-tcpPort", port, "-tcpAllowOthers", "-ifExists");
182
                } else {
183
//                    theServer = Server.createTcpServer("-tcpPort", port, "-ifExists");
184
                }
185
//                theServer.start();
186
//                server = theServer;
187
                LOGGER.info("MDB Server started" );
188
//                LOGGER.info("  port  :"+ server.getPort());
189
//                LOGGER.info("  URL  :"+ server.getURL());
190
//                LOGGER.info("  status:"+ server.getStatus());
191
                // Tanto si consigue lanzar el server como si no, no lo vuelve a intentar
192
                startServer = false;
193
            }
194

    
195
        }
196

    
197
        @Override
198
        public String toString() {
199
            StringBuilder builder = new StringBuilder();
200
            builder.append(" url=").append(connectionParameters.getUrl());
201
            builder.append(" driver name=").append(connectionParameters.getJDBCDriverClassName());
202
            builder.append(" user=").append(connectionParameters.getUser());
203
            return builder.toString();
204
        }
205
        
206
        public Connection getConnection() throws SQLException {
207
            File f = this.connectionParameters.getFile();
208
            boolean newdb = f!=null && !f.exists();
209
            
210
            if (this.dataSource == null) {
211
                this.dataSource = this.createDataSource();               
212
            }
213
            Connection conn = this.dataSource.getConnection();
214
////            try {
215
//////                conn.createStatement().execute("SELECT TOP 1 SRID FROM SPATIAL_REF_SYS");
216
////            } catch(SQLException ex) {
217
//////                H2GISExtension.load(conn);
218
////            }
219
//            try {
220
////                conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS PUBLIC;SET SCHEMA PUBLIC");
221
//            } catch(SQLException ex) {
222
//                // Ignore this error.
223
//            }
224
            if (newdb) {
225
                //crea tablas
226
                //
227
            }
228
            return conn;
229
        }
230

    
231
        private BasicDataSource createDataSource() throws SQLException {
232
            if (!this.isRegistered()) {
233
                this.registerDriver();
234
            }
235
            startServer();
236
            MDBConnectionParameters params = connectionParameters;
237

    
238
            BasicDataSource ds = new BasicDataSource();
239
            ds.setDriverClassName(params.getJDBCDriverClassName());
240
            if( !StringUtils.isEmpty(params.getUser()) ) {
241
                ds.setUsername(params.getUser());
242
            }
243
            if( !StringUtils.isEmpty(params.getPassword()) ) {
244
                ds.setPassword(params.getPassword());
245
            }
246
            ds.setUrl(params.getUrl());
247

    
248
            ds.setMaxWait(60L * 1000);
249
            return ds;
250
        }
251

    
252
        private boolean isRegistered() {
253
            return needRegisterDriver;
254
        }
255

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

    
272
        @Override
273
        public void dispose() {
274
            if( this.dataSource!=null ) {
275
                try {
276
                    this.dataSource.close();
277
                } catch (SQLException ex) {
278
                    LOGGER.warn("Can't close BasicDataSource", ex);
279
                }
280
                this.dataSource = null;
281
            }
282
            this.connectionParameters = null;
283
        }
284

    
285
    }
286

    
287
    private ConnectionProvider connectionProvider = null;
288
    
289
        /**
290
     * Constructor for use only for testing purposes.
291
     * 
292
     * @param connectionParameters
293
     * @param connectionProvider
294
     */
295
    public MDBHelper(JDBCConnectionParameters connectionParameters, ConnectionProvider connectionProvider) { 
296
        super(connectionParameters);
297
        this.srssolver = new SRSSolverDumb(this);
298
        this.connectionProvider = connectionProvider;
299
    }
300
 
301
    public MDBHelper(JDBCConnectionParameters connectionParameters) {
302
        super(connectionParameters);
303
        this.srssolver = new SRSSolverDumb(this);
304
    }
305

    
306
    @Override
307
    public synchronized JDBCConnection  getConnection() throws AccessResourceException {
308
        try {
309
            MDBConnectionParameters connectionParameters = this.getConnectionParameters();
310
            JDBCConnection conn = (JDBCConnection) DataTransactionServices.getConnection(transaction, connectionParameters.getUrl());
311
            if( conn != null ) {
312
                return conn;
313
            }
314
            if (this.connectionProvider == null) {
315
              if( this.getConnectionParameters()==null ) {
316
                return null;
317
              }
318
              this.connectionProvider = new ConnectionProviderImpl(this.getConnectionParameters());
319
            }
320
            JDBCConnection connection = new JDBCConnectionBase(
321
                    this.transaction, 
322
                    this.connectionProvider.getConnection(), 
323
                    connectionParameters.getUrl()
324
            );
325
            if( LOGGER.isDebugEnabled() ) {
326
                LOGGER.debug("getConnection: connection = "+connection.hashCode()+ connectionProvider.toString());
327
            }
328
            return connection;
329
        } catch (SQLException ex) {
330
            throw new AccessResourceException(MDBLibrary.NAME, ex);
331
        }
332
    }
333

    
334
    @Override
335
    public void closeConnection(Connection connection) {
336
      if( connection!=null ) { // In test ???
337
        LOGGER.debug("closeConnection: connection = "+connection.hashCode());
338
      }
339
      super.closeConnection(connection);
340
    }
341
    
342
    @Override
343
    public MDBConnectionParameters getConnectionParameters() {
344
        return (MDBConnectionParameters) super.getConnectionParameters();
345
    }
346
    
347
    @Override
348
    public String getConnectionURL() {
349
        return getConnectionURL(this.getConnectionParameters());
350
    }
351

    
352
    @Override
353
    protected String getResourceType() {
354
        return MDBLibrary.NAME;
355
    }
356

    
357
    @Override
358
    public String getProviderName() {
359
        return MDBLibrary.NAME;
360
    }
361

    
362
    @Override
363
    public JDBCSQLBuilderBase createSQLBuilder() {
364
        return new MDBSQLBuilder(this);
365
    }
366
    
367
    @Override
368
    public OperationsFactory getOperations() {
369
        if (this.operationsFactory == null) {
370
            this.operationsFactory = new MDBOperationsFactory(this);
371
        }
372
        return operationsFactory;
373
    }
374

    
375
    @Override
376
    public GeometrySupportType getGeometrySupportType() {
377
        return GeometrySupportType.WKB;
378
    }
379

    
380
    @Override
381
    public boolean hasSpatialFunctions() {
382
        return false;
383
    }
384

    
385
    @Override
386
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
387
        return true;
388
    }
389

    
390
    @Override
391
    public String getQuoteForIdentifiers() {
392
        return "\"";
393
    }
394

    
395
    @Override
396
    public boolean allowAutomaticValues() {
397
        return true;
398
    }
399

    
400
    @Override
401
    public boolean supportOffsetInSelect() {
402
        return true;
403
    }
404

    
405
    @Override
406
    public String getQuoteForStrings() {
407
        return "'";
408
    }
409

    
410
    @Override
411
    public String getSourceId(JDBCStoreParameters parameters) {
412
        return parameters.getDBName() + "." + 
413
               parameters.getSchema()+ "." + 
414
               parameters.getTable();
415
    }
416

    
417
    @Override
418
    public JDBCNewStoreParameters createNewStoreParameters() {
419
        return new MDBNewStoreParameters();
420
    }
421

    
422
    @Override
423
    public JDBCStoreParameters createOpenStoreParameters() {
424
        return new MDBStoreParameters();
425
    }
426

    
427
    @Override
428
    public JDBCServerExplorerParameters createServerExplorerParameters() {
429
        return new MDBExplorerParameters();
430
    }
431

    
432
    @Override
433
    public JDBCServerExplorer createServerExplorer(
434
            JDBCServerExplorerParameters parameters, 
435
            DataServerExplorerProviderServices providerServices
436
        ) throws InitializeException {
437
        
438
        JDBCServerExplorer explorer = new JDBCServerExplorerBase(
439
                parameters, 
440
                providerServices, 
441
                this
442
        );
443
        this.initialize(explorer, parameters, null);
444
        return explorer;
445
    }
446
    
447
    @Override
448
  public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
449
    try {
450
      Object value;
451
      Clob clob;
452
      String strGeom;
453
      switch (this.getGeometrySupportType()) {
454
        case NATIVE:
455
        case WKB:
456
            clob = rs.getClob(index);
457
            if (clob ==null) {
458
                return null;
459
            }
460
            strGeom = new String(IOUtils.toCharArray(clob.getCharacterStream()));
461
            clob.free();
462
            return this.getGeometryManager().createFrom(strGeom);
463
        case EWKB:
464
            clob = rs.getClob(index);
465
            if (clob ==null) {
466
                return null;
467
            }
468
            strGeom = new String(IOUtils.toCharArray(clob.getCharacterStream()));
469
            clob.free();
470
            return this.getGeometryManager().createFrom(strGeom);
471
        case WKT:
472
        default:
473
          value = rs.getString(index);
474
          if (value == null) {
475
            return null;
476
          }
477
          return this.getGeometryManager().createFrom((String) value);
478

    
479
      }
480
    } catch (Exception ex) {
481
      throw new JDBCCantFetchValueException(ex);
482
    }
483
  }
484
}