Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.plugin / org.gvsig.sqlite / org.gvsig.sqlite.provider / src / main / java / org / gvsig / sqlite / dal / SQLiteHelper.java @ 47542

History | View | Annotate | Download (15.4 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.sqlite.dal;
23

    
24
import java.io.File;
25
import java.sql.Connection;
26
import java.sql.ResultSet;
27
import java.sql.SQLException;
28
import org.gvsig.expressionevaluator.GeometryExpressionBuilderHelper.GeometrySupportType;
29
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_NAME;
30
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_CONFIGURATION_VALUE;
31
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_NAME;
32
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.FIELD_RESOURCES_RESOURCE;
33
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_CONFIGURATION_NAME;
34
import static org.gvsig.fmap.dal.DatabaseWorkspaceManager.TABLE_RESOURCES_NAME;
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.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.JDBCDriverClassNotFoundException;
45
import org.gvsig.fmap.dal.store.jdbc2.JDBCConnection;
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.AbstractConnectionProvider;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.ConnectionProvider;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCConnectionBase;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCHelperBase;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.JDBCSQLBuilderBase;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolver;
55
import org.gvsig.fmap.dal.store.jdbc2.spi.SRSSolverDumb;
56
import org.gvsig.fmap.geom.Geometry;
57
import org.gvsig.fmap.geom.aggregate.MultiLine;
58
import org.gvsig.fmap.geom.aggregate.MultiPoint;
59
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
60
import org.gvsig.fmap.geom.exception.CreateGeometryException;
61
import org.gvsig.fmap.geom.primitive.Primitive;
62
import org.gvsig.fmap.geom.type.GeometryType;
63
import org.gvsig.sqlite.dal.functions.Functions;
64
import org.gvsig.sqlite.dal.geopackage.GeopackageGeometryParser;
65
import org.gvsig.sqlite.dal.geopackage.GeopackageUtils;
66
import org.gvsig.sqlite.dal.operations.SQLiteOperationsFactory;
67
import org.gvsig.tools.dispose.DisposeUtils;
68
import org.slf4j.Logger;
69
import org.slf4j.LoggerFactory;
70
import org.sqlite.JDBC;
71
import org.sqlite.SQLiteConfig;
72
import org.sqlite.SQLiteConfig.TransactionMode;
73
import org.sqlite.SQLiteConnection;
74

    
75
@SuppressWarnings("UseSpecificCatch")
76
public class SQLiteHelper extends JDBCHelperBase {
77

    
78
    /*
79
        https://www.jpab.org/Hibernate/H2/embedded/Hibernate/SQLite/embedded.html
80
    */
81
    
82
    @SuppressWarnings("FieldNameHidesFieldInSuperclass")
83
    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLiteHelper.class);
84

    
85
    public static class ConnectionProviderImpl extends AbstractConnectionProvider implements ConnectionProvider {
86

    
87
        private static boolean needRegisterDriver = true;
88

    
89
        private SQLiteConnectionParameters connectionParameters;
90

    
91
        public ConnectionProviderImpl(SQLiteConnectionParameters connectionParameters) {
92
            this.connectionParameters = connectionParameters;
93
        }
94

    
95
        @Override
96
        public synchronized Connection getConnection() throws SQLException {
97
            if (!this.isRegistered()) {
98
                this.registerDriver();
99
            }
100

    
101
            File f = SQLiteUtils.getLocalFile(connectionParameters);
102
            boolean newdb = f != null && !f.exists();
103

    
104
            SQLiteConfig config = new SQLiteConfig();
105
            config.setSharedCache(true);
106
            config.enableLoadExtension(true);
107
            config.setTransactionMode(TransactionMode.IMMEDIATE);
108
//            config.setSynchronous(SQLiteConfig.SynchronousMode.OFF);
109
            config.setPragma(SQLiteConfig.Pragma.CASE_SENSITIVE_LIKE, "true");
110

    
111
            SQLiteConnection conn;
112

    
113
            try {
114
                conn = org.sqlite.JDBC.createConnection(connectionParameters.getUrl(), config.toProperties());
115
            } catch (Throwable th) {
116
                throw th;
117
            }
118

    
119
            Functions.register_all(conn);
120

    
121
            if (newdb) {
122
                String[] sqls2 = new String[]{
123
                    "CREATE CACHED TABLE PUBLIC.\"" + TABLE_RESOURCES_NAME + "\"(\"" + FIELD_RESOURCES_NAME + "\" VARCHAR(150) NOT NULL, \"" + FIELD_RESOURCES_RESOURCE + "\" BLOB DEFAULT NULL)",
124
                    "ALTER TABLE PUBLIC.\"" + TABLE_RESOURCES_NAME + "\" ADD CONSTRAINT PUBLIC.CONSTRAINT_E PRIMARY KEY(\"" + FIELD_RESOURCES_NAME + "\")",
125
                    "CREATE CACHED TABLE PUBLIC.\"" + TABLE_CONFIGURATION_NAME + "\"(\"" + FIELD_CONFIGURATION_NAME + "\" VARCHAR(200) NOT NULL, \"" + FIELD_CONFIGURATION_VALUE + "\" CLOB DEFAULT NULL)",
126
                    "ALTER TABLE PUBLIC.\"" + TABLE_CONFIGURATION_NAME + "\" ADD CONSTRAINT PUBLIC.CONSTRAINT_2 PRIMARY KEY(\"" + FIELD_CONFIGURATION_NAME + "\")",};
127
                for (String sql : sqls2) {
128
                    try {
129
                        conn.createStatement().execute(sql);
130
                    } catch (SQLException ex) {
131
                        LOGGER.debug("Can't configure gvsig tables.", ex);
132
                        LOGGER.warn("Can't configure gvsig tables. " + sql);
133
                        // Ignore this error.
134
                    }
135
                }
136
            }
137
            return conn;
138
        }
139

    
140
        private boolean isRegistered() {
141
            return needRegisterDriver;
142
        }
143

    
144
        @Override
145
        public void registerDriver() throws SQLException {
146
            String className = this.connectionParameters.getJDBCDriverClassName();
147
            if (className == null) {
148
                return;
149
            }
150
            try {
151
                Class theClass = Class.forName(className);
152
                if (theClass == null) {
153
                    throw new JDBCDriverClassNotFoundException(SQLiteLibrary.NAME, className);
154
                }
155
            } catch (Exception e) {
156
                throw new SQLException("Can't register JDBC driver '" + className + "'.", e);
157
            }
158
            needRegisterDriver = false;
159
        }
160

    
161
        @Override
162
        public void dispose() {
163
            if (!DisposeUtils.release(this)) {
164
                return;
165
            }
166
            this.connectionParameters = null;
167
        }
168

    
169
        @Override
170
        public boolean isDisposed() {
171
            return this.connectionParameters == null;
172
        }
173

    
174
    }
175

    
176
    private ConnectionProvider connectionProvider = null;
177

    
178
    /**
179
     * Constructor for use only for testing purposes.
180
     *
181
     * @param connectionParameters
182
     * @param connectionProvider
183
     */
184
    public SQLiteHelper(JDBCConnectionParameters connectionParameters, ConnectionProvider connectionProvider) {
185
        super(connectionParameters);
186
        this.srssolver = new SRSSolverDumb(this);
187
        this.connectionProvider = connectionProvider;
188
    }
189

    
190
    public SQLiteHelper(JDBCConnectionParameters connectionParameters) {
191
        super(connectionParameters);
192
        this.srssolver = null; // GeopackageUtils.createSRSSolver(this);
193
    }
194

    
195
    @Override
196
    public synchronized JDBCConnection getConnection() throws AccessResourceException {
197
        try {
198
            SQLiteConnectionParameters connectionParameters = this.getConnectionParameters();
199
            JDBCConnection conn = (JDBCConnection) DataTransactionServices.getConnection(
200
                    transaction,
201
                    this.getConnectionProviderKey(connectionParameters)
202
            );
203
            if (conn != null) {
204
                return conn;
205
            }
206
            if (this.connectionProvider == null) {
207
                if (connectionParameters == null) {
208
                    return null; // Testing mode?
209
                }
210
                this.connectionProvider = new ConnectionProviderImpl(connectionParameters);
211
            }
212
            JDBCConnection connection = new JDBCConnectionBase(
213
                    this.transaction,
214
                    this.connectionProvider.getConnection(),
215
                    this.getConnectionProviderKey(connectionParameters)
216
            );
217
            if (LOGGER.isDebugEnabled()) {
218
                LOGGER.debug("[" + JDBCUtils.getConnId(connection.get()) + "] getConnection " + connectionProvider.getStatus() + " " + connectionProvider.toString());
219
            }
220
            return connection;
221
        } catch (SQLException ex) {
222
            throw new AccessResourceException(SQLiteLibrary.NAME, ex);
223
        }
224
    }
225

    
226
    @Override
227
    public SQLiteConnectionParameters getConnectionParameters() {
228
        return (SQLiteConnectionParameters) super.getConnectionParameters();
229
    }
230

    
231
    @Override
232
    public String getConnectionURL() {
233
        return SQLiteUtils.getConnectionURL(this.getConnectionParameters());
234
    }
235

    
236
    @Override
237
    protected String getResourceType() {
238
        return SQLiteLibrary.NAME;
239
    }
240

    
241
    @Override
242
    public String getProviderName() {
243
        return SQLiteLibrary.NAME;
244
    }
245

    
246
    @Override
247
    public JDBCSQLBuilderBase createSQLBuilder() {
248
        return new SQLiteSQLBuilder(this);
249
    }
250

    
251
    @Override
252
    public OperationsFactory getOperations() {
253
        if (this.operationsFactory == null) {
254
            this.operationsFactory = new SQLiteOperationsFactory(this);
255
        }
256
        return operationsFactory;
257
    }
258

    
259
    @Override
260
    public GeometrySupportType getGeometrySupportType() {
261
        return GeometrySupportType.NATIVE;
262
//        return GeometrySupportType.EWKB;
263
    }
264

    
265
    @Override
266
    public boolean hasSpatialFunctions() {
267
        return true;
268
    }
269

    
270
    @Override
271
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
272
        return true;
273
    }
274

    
275
    @Override
276
    public String getQuoteForIdentifiers() {
277
        return "\"";
278
    }
279

    
280
    @Override
281
    public boolean allowAutomaticValues() {
282
        return true;
283
    }
284

    
285
    @Override
286
    public boolean supportOffsetInSelect() {
287
        return true;
288
    }
289

    
290
    @Override
291
    public String getQuoteForStrings() {
292
        return "'";
293
    }
294

    
295
    @Override
296
    public String getSourceId(JDBCStoreParameters parameters) {
297
        return parameters.getDBName() + "."
298
                + parameters.getSchema() + "."
299
                + parameters.getTable();
300
    }
301

    
302
    @Override
303
    public JDBCNewStoreParameters createNewStoreParameters() {
304
        return new SQLiteNewStoreParameters();
305
    }
306

    
307
    @Override
308
    public JDBCStoreParameters createOpenStoreParameters() {
309
        return new SQLiteStoreParameters();
310
    }
311

    
312
    @Override
313
    public JDBCServerExplorerParameters createServerExplorerParameters() {
314
        return new SQLiteExplorerParameters();
315
    }
316

    
317
    public Geometry forceGeometryType(GeometryType geomtype, Geometry geom) throws CreateGeometryException {
318
        if (geom == null) {
319
            return null;
320
        }
321
        switch (geomtype.getType()) {
322
            case Geometry.TYPES.MULTIPOLYGON:
323
                if (geom.getType() == Geometry.TYPES.POLYGON) {
324
                    MultiPolygon x = getGeometryManager().createMultiPolygon(geomtype.getSubType());
325
                    x.addPrimitive((Primitive) geom);
326
                    geom = x;
327
                }
328
                break;
329
            case Geometry.TYPES.MULTILINE:
330
                if (geom.getType() == Geometry.TYPES.LINE) {
331
                    MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
332
                    x.addPrimitive((Primitive) geom);
333
                    geom = x;
334
                }
335
                break;
336
            case Geometry.TYPES.MULTIPOINT:
337
                if (geom.getType() == Geometry.TYPES.POINT) {
338
                    MultiLine x = getGeometryManager().createMultiLine(geomtype.getSubType());
339
                    x.addPrimitive((Primitive) geom);
340
                    geom = x;
341
                }
342
                break;
343
            case Geometry.TYPES.POLYGON:
344
                if (geom.getType() == Geometry.TYPES.MULTIPOLYGON) {
345
                    MultiPolygon x = (MultiPolygon) geom;
346
                    if (x.getPrimitivesNumber() == 1) {
347
                        geom = x.getPrimitiveAt(0);
348
                    }
349
                }
350
                break;
351
            case Geometry.TYPES.LINE:
352
                if (geom.getType() == Geometry.TYPES.MULTILINE) {
353
                    MultiLine x = (MultiLine) geom;
354
                    if (x.getPrimitivesNumber() == 1) {
355
                        geom = x.getPrimitiveAt(0);
356
                    }
357
                }
358
                break;
359
            case Geometry.TYPES.POINT:
360
                if (geom.getType() == Geometry.TYPES.MULTIPOINT) {
361
                    MultiPoint x = (MultiPoint) geom;
362
                    if (x.getPrimitivesNumber() == 1) {
363
                        geom = x.getPrimitiveAt(0);
364
                    }
365
                }
366
        }
367
        return geom;
368
    }
369

    
370
    @Override
371
    public SRSSolver getSRSSolver() {
372
        if (this.srssolver == null) {
373
            try {
374
                this.srssolver = GeopackageUtils.createSRSSolver((SQLiteConnection) this.getConnection().get());
375
            } catch (Exception ex) {
376
                throw new RuntimeException("Can't get SRSSolver", ex);
377
            }
378
        }
379
        return this.srssolver;
380
    }
381

    
382
    @Override
383
    public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
384
        try {
385
            if( this.getGeometrySupportType() == GeometrySupportType.NATIVE ) {
386
                byte[] bytes = rs.getBytes(index);
387
                if( GeopackageUtils.isGeopackageGeometry(bytes) ) {
388
                    GeopackageGeometryParser parser = GeopackageUtils.createGeometryParser();
389
                    Geometry geom = parser.parseToGeometry(null, bytes);
390
                    return geom;
391
                }
392
            }
393
        } catch (Exception ex) {
394
            LOGGER.debug("Can't process native geometry", ex);
395
        }
396
        return super.getGeometryFromColumn(rs, index);
397
    }
398

    
399
    @Override
400
    public JDBCServerExplorer createServerExplorer(
401
            JDBCServerExplorerParameters parameters, 
402
            DataServerExplorerProviderServices providerServices
403
        ) throws InitializeException {
404
        
405
        JDBCServerExplorer explorer = new SQLiteExplorer(
406
                parameters, 
407
                providerServices, 
408
                this
409
        );
410
        this.initialize(explorer, parameters, null);
411
        return explorer;
412
    }
413
    
414
 }