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

History | View | Annotate | Download (16.3 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.store.mdb.operations.MDBOperationsFactory;
40
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
42
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
43
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
44
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
45
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCDriverClassNotFoundException;
46
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
47
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
48
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
49
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCServerExplorerBase;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
54
import org.gvsig.fmap.geom.Geometry;
55
//import org.h2.tools.Server;
56
//import org.h2gis.ext.H2GISExtension;
57
import org.slf4j.Logger;
58
import org.slf4j.LoggerFactory;
59

    
60
@SuppressWarnings("UseSpecificCatch")
61
public class MDBHelper extends JDBCHelperBase {
62

    
63
    static final Logger LOGGER = LoggerFactory.getLogger(MDBHelper.class);
64

    
65
    public static final String MDB_JDBC_DRIVER = "net.ucanaccess.jdbc.UcanaccessDriver";
66

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

    
112
    public static class ConnectionProviderImpl implements ConnectionProvider {
113

    
114
        private static boolean needRegisterDriver = true;
115

    
116
        private BasicDataSource dataSource = null;
117

    
118
        private MDBConnectionParameters connectionParameters;
119

    
120
//        private static Server server = null;
121
        private static String server = null;
122
        private static boolean startServer = true;
123

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

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

    
192
        }
193

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

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

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

    
245
            ds.setMaxWait(60L * 1000);
246
            return ds;
247
        }
248

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

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

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

    
282
    }
283

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

    
303
    @Override
304
    public synchronized Connection  getConnection() throws AccessResourceException {
305
        try {
306
            if (this.connectionProvider == null) {
307
              MDBConnectionParameters connectionParameters = this.getConnectionParameters();
308
              if( connectionParameters==null ) {
309
                return null; // Testing mode?
310
              }
311
              this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
312
            }
313
            Connection connection = this.connectionProvider.getConnection();
314
            if( LOGGER.isDebugEnabled() ) {
315
                LOGGER.debug("getConnection: connection = "+connection.hashCode()+ connectionProvider.toString());
316
            }
317
            return connection;
318
        } catch (SQLException ex) {
319
            throw new AccessResourceException(MDBLibrary.NAME, ex);
320
        }
321
    }
322

    
323
    @Override
324
    public void closeConnection(Connection connection) {
325
      if( connection!=null ) { // In test ???
326
        LOGGER.debug("closeConnection: connection = "+connection.hashCode());
327
      }
328
      super.closeConnection(connection);
329
    }
330
    
331
    @Override
332
    public MDBConnectionParameters getConnectionParameters() {
333
        return (MDBConnectionParameters) super.getConnectionParameters();
334
    }
335
    
336
    @Override
337
    public String getConnectionURL() {
338
        return getConnectionURL(this.getConnectionParameters());
339
    }
340

    
341
    @Override
342
    protected String getResourceType() {
343
        return MDBLibrary.NAME;
344
    }
345

    
346
    @Override
347
    public String getProviderName() {
348
        return MDBLibrary.NAME;
349
    }
350

    
351
    @Override
352
    public JDBCSQLBuilderBase createSQLBuilder() {
353
        return new MDBSQLBuilder(this);
354
    }
355
    
356
    @Override
357
    public OperationsFactory getOperations() {
358
        if (this.operationsFactory == null) {
359
            this.operationsFactory = new MDBOperationsFactory(this);
360
        }
361
        return operationsFactory;
362
    }
363

    
364
    @Override
365
    public GeometrySupportType getGeometrySupportType() {
366
        return GeometrySupportType.WKB;
367
    }
368

    
369
    @Override
370
    public boolean hasSpatialFunctions() {
371
        return false;
372
    }
373

    
374
    @Override
375
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
376
        return true;
377
    }
378

    
379
    @Override
380
    public String getQuoteForIdentifiers() {
381
        return "\"";
382
    }
383

    
384
    @Override
385
    public boolean allowAutomaticValues() {
386
        return true;
387
    }
388

    
389
    @Override
390
    public boolean supportOffsetInSelect() {
391
        return true;
392
    }
393

    
394
    @Override
395
    public String getQuoteForStrings() {
396
        return "'";
397
    }
398

    
399
    @Override
400
    public String getSourceId(JDBCStoreParameters parameters) {
401
        return parameters.getDBName() + "." + 
402
               parameters.getSchema()+ "." + 
403
               parameters.getTable();
404
    }
405

    
406
    @Override
407
    public JDBCNewStoreParameters createNewStoreParameters() {
408
        return new MDBNewStoreParameters();
409
    }
410

    
411
    @Override
412
    public JDBCStoreParameters createOpenStoreParameters() {
413
        return new MDBStoreParameters();
414
    }
415

    
416
    @Override
417
    public JDBCServerExplorerParameters createServerExplorerParameters() {
418
        return new MDBExplorerParameters();
419
    }
420

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

    
468
      }
469
    } catch (Exception ex) {
470
      throw new JDBCCantFetchValueException(ex);
471
    }
472
  }
473
}