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.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / JDBCHelperBase.java @ 44191

History | View | Annotate | Download (17.5 KB)

1
package org.gvsig.fmap.dal.store.jdbc2.spi;
2

    
3
import org.gvsig.fmap.dal.store.jdbc2.impl.ResulSetControlerBase;
4
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.OperationsFactoryBase;
5
import java.sql.Connection;
6
import java.sql.ResultSet;
7
import org.apache.commons.lang3.StringUtils;
8
import org.apache.commons.lang3.mutable.MutableBoolean;
9
import org.gvsig.expressionevaluator.Code;
10
import org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType;
11
import static org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType.EWKB;
12
import static org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType.NATIVE;
13
import static org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType.WKB;
14
import static org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType.WKT;
15
import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
16
import org.gvsig.expressionevaluator.ExpressionEvaluatorManager;
17
import org.gvsig.expressionevaluator.Function;
18
import org.gvsig.fmap.dal.DataTypes;
19
import org.gvsig.fmap.dal.exception.DataException;
20
import org.gvsig.fmap.dal.exception.InitializeException;
21
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
22
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
23
import org.gvsig.fmap.dal.feature.FeatureType;
24

    
25
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
26
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
27
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
28
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
29
import org.gvsig.fmap.dal.spi.DataServerExplorerProviderServices;
30
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
31
import org.gvsig.fmap.dal.store.db.DBHelper;
32
import org.gvsig.fmap.dal.store.jdbc.JDBCConnectionParameters;
33
import org.gvsig.fmap.dal.store.jdbc.JDBCLibrary;
34
import org.gvsig.fmap.dal.store.jdbc.JDBCNewStoreParameters;
35
import org.gvsig.fmap.dal.store.jdbc.JDBCResource;
36
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
37
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
38
import org.gvsig.fmap.dal.store.jdbc.exception.JDBCCantFetchValueException;
39
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
40
import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorer;
41
import org.gvsig.fmap.dal.store.jdbc2.JDBCStoreProvider;
42
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
43
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
44
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
45
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler.ResultSetEntry;
46
import org.gvsig.fmap.geom.Geometry;
47
import org.gvsig.fmap.geom.GeometryLocator;
48
import org.gvsig.fmap.geom.GeometryManager;
49
import org.gvsig.tools.dispose.impl.AbstractDisposable;
50
import org.gvsig.tools.evaluator.Evaluator;
51
import org.gvsig.tools.exception.BaseException;
52
import org.gvsig.tools.exception.NotYetImplemented;
53
import org.gvsig.tools.visitor.VisitCanceledException;
54
import org.gvsig.tools.visitor.Visitor;
55
import org.slf4j.Logger;
56
import org.slf4j.LoggerFactory;
57

    
58
@SuppressWarnings("UseSpecificCatch")
59
public class JDBCHelperBase extends AbstractDisposable implements ResourceConsumer, JDBCHelper {
60

    
61
    private static final boolean ALLOW_AUTOMATIC_VALUES = true;
62
    private static final String QUOTE_FOR_USE_IN_IDENTIFIERS = "\"";
63
    private static final String QUOTE_FOR_USE_IN_STRINGS = "'";
64

    
65
    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCHelperBase.class);
66

    
67
    private ResulSetControler resulSetControler = null;
68

    
69
    // Quien ha creado este helper.
70
    // Se le reenviaran las notificaciones del recurso asociado al helper.
71
    private ResourceConsumer helperClient = null;
72

    
73
    private GeometryManager geometryManager = null;
74

    
75
    private JDBCConnectionParameters connectionParameters;
76

    
77
    private JDBCStoreProvider store;    
78
    
79
    protected OperationsFactory operationsFactory = null;
80
    
81
    protected SRSSolver srssolver;
82
    
83
    public JDBCHelperBase(JDBCConnectionParameters connectionParameters) {
84
        this.connectionParameters = connectionParameters;
85
        
86
        // If a particular treatment is required to convert SRS to the 
87
        // BBDD format, overwrite JDBCSRSsBase and use it instead of JDBCSRSsDumb.
88
        this.srssolver = new SRSSolverDumb(this);
89
    }
90

    
91
    protected void initialize(
92
            ResourceConsumer helperClient,
93
            JDBCConnectionParameters connectionParameters,
94
            JDBCStoreProvider store
95
        ) {
96
        this.store = store;
97
        this.helperClient = helperClient;
98
        this.connectionParameters = connectionParameters;
99
        initializeResource(connectionParameters);        
100
    }
101
    
102
    protected String getResourceType() {
103
        return JDBCResource.NAME;
104
    }
105

    
106
    @Override
107
    public String getProviderName() {
108
        return JDBCLibrary.NAME;
109
    }
110
        
111
    @Override
112
    public GeometrySupportType getGeometrySupportType() {
113
        // El proveedor generico de JDBC guadara las geoemtrias como WKT
114
        return GeometrySupportType.WKT;
115
    }
116

    
117
    @Override
118
    public boolean hasSpatialFunctions() {
119
        // Por defecto el proveedor generico de JDBC asume que la BBDD no 
120
        // tiene soporte para funciones espaciales.
121
        return false;
122
    }
123

    
124
    @Override
125
    public boolean allowNestedOperations() {
126
        return false;
127
    }
128
    
129
    @Override
130
    public boolean canWriteGeometry(int geometryType, int geometrySubtype) {
131
        // Como va a guardar las geometrias en WKT, puede escribirlas todas.
132
        return true;
133
    }
134

    
135
    @Override
136
    public JDBCSQLBuilderBase createSQLBuilder() {
137
        return new JDBCSQLBuilderBase(this);
138
    }
139

    
140
    @Override
141
    public String getQuoteForIdentifiers() {
142
        return QUOTE_FOR_USE_IN_IDENTIFIERS;
143
    }
144

    
145
    @Override
146
    public boolean allowAutomaticValues() {
147
        return ALLOW_AUTOMATIC_VALUES;
148
    }
149

    
150
    @Override
151
    public boolean supportOffsetInSelect() {
152
        // Asumimos que la BBDD soporta OFFSET
153
        return true;
154
    }
155
    
156
    @Override
157
    public String getQuoteForStrings() {
158
        return QUOTE_FOR_USE_IN_STRINGS;
159
    }
160

    
161
    @Override
162
    public boolean supportFilter(Evaluator filter) {
163
        // No podemos filtrar cuando:
164
        // - Hay una subquery especificada en los parametros 
165
        // - Si hay un filtro y el getSQL devuelbe null.
166
        // - Si se esta usando alguna funcion no-sql en el getSQL
167
        // - Si se estan usando funciones OGC y no soportamos funciones espaciales
168
        // 
169
        // Un proveedor especifico podria sobreescribir el metodo,
170
        // para hilar mas fino al comprobar si soporta el filtro o no.
171
        //
172
        
173
        if (this.useSubquery()) {
174
            // Se esta usando una subquery en los parametros de acceso a la
175
            // BBDD, asi que no podemos filtrar.
176
            return false;
177
        }
178
        if (filter == null) {
179
            // No hay que filtrar nada, asi que se p?ede.
180
            return true;
181
        }
182
        String sql = filter.getSQL();
183
        if (StringUtils.isEmpty(sql)) {
184
            // Hay un filtro, pero la SQL es null, con lo que no podemos
185
            // filtrar por el.
186
            return false;
187
        }
188

    
189
        // Ahora vamos a comprobar que las funciones que se usan son 
190
        // compatibles sql, y que no se usan funciones OGC si el 
191
        // proveedor dice que no soporta funciones espaciales.
192
        final MutableBoolean isCompatible = new MutableBoolean(true);
193
        final boolean supportSpatialFunctions = this.hasSpatialFunctions();
194
        ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
195
        Code code = manager.compile(sql);
196
        try {
197
            code.accept(new Visitor() {
198
                @Override
199
                public void visit(Object code_obj) throws VisitCanceledException, BaseException {
200
                    Code code = (Code) code_obj;
201
                    if ( code.code()==Code.CALLER ) {
202
                        Code.Caller caller = (Code.Caller) code;
203
                        Function function = caller.function();
204
                        if( function==null ) {
205
                            isCompatible.setValue(false);
206
                            throw new VisitCanceledException();
207
                        }
208
                        if( !function.isSQLCompatible() ) {
209
                            isCompatible.setValue(false);
210
                            throw new VisitCanceledException();
211
                        }
212
                        if( !supportSpatialFunctions ) {
213
                            if( StringUtils.equalsIgnoreCase(function.group(),Function.GROUP_OGC) ) {
214
                                isCompatible.setValue(false);
215
                                throw new VisitCanceledException();
216
                            }
217
                        }
218
                    }
219
                }
220
            });
221

    
222
        } catch (VisitCanceledException ex) {
223
            // Do nothing
224
        } catch (Exception ex) {
225
            LOGGER.warn("Can't calculate if is SQL compatible.", ex);
226
        }
227
        
228
        return isCompatible.booleanValue();
229
    }
230
    
231
    @Override
232
    public boolean supportOrder(FeatureQueryOrder order) {
233
        if (this.useSubquery()) {
234
            return false;
235
        }
236
        if (order == null) {
237
            return true;
238
        }
239
        for( FeatureQueryOrder.FeatureQueryOrderMember member : order.members() ) {
240
            if (member.hasEvaluator()) {
241
                if( !this.supportFilter(member.getEvaluator()) ) {
242
                    return false;
243
                }
244
            }            
245
        }
246
        return true;
247
    }
248
    
249
    @Override
250
    public OperationsFactory getOperations() {
251
        if (this.operationsFactory== null) {
252
            this.operationsFactory = new OperationsFactoryBase(this);
253
        }
254
        return operationsFactory;
255
    }
256
    
257
    protected void initializeResource(JDBCConnectionParameters params) {
258
//        Object[] resourceParams = new Object[]{
259
//            params.getUrl(),
260
//            params.getHost(),
261
//            params.getPort(),
262
//            params.getDBName(),
263
//            params.getUser(),
264
//            params.getPassword(),
265
//            params.getJDBCDriverClassName()
266
//        };
267
//
268
//        try {
269
//            ResourceManagerProviderServices manager
270
//                    = (ResourceManagerProviderServices) DALLocator.getResourceManager();
271
//            JDBCResource resource = (JDBCResource) manager.createAddResource(
272
//                    this.getResourceType(),
273
//                    resourceParams
274
//            );
275
//            this.resource = resource;
276
//            this.resource.addConsumer(this);
277
//        } catch (InitializeException ex) {
278
//            logger.debug("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
279
//            throw new RuntimeException("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
280
//        }
281

    
282
    }
283

    
284
    @Override
285
    public String getSourceId() {
286
        return this.store.getSourceId();
287
    }
288
    
289
    @Override
290
    public JDBCResource getResource() {
291
        return null;
292
//        return this.resource;
293
    }
294

    
295
    @Override
296
    public Connection getConnection() throws AccessResourceException {
297
        throw new NotYetImplemented();
298
    }
299

    
300
    @Override
301
    public Connection getConnectionWritable() throws AccessResourceException {
302
        return this.getConnection();
303
    }
304

    
305
    @Override
306
    public String getConnectionURL() {
307
        return null;
308
    }
309

    
310
    @Override
311
    public JDBCConnectionParameters getConnectionParameters() {
312
        return connectionParameters;
313
    }
314

    
315
    @Override
316
    public void closeConnection(Connection connection) {
317
        if( connection != null ) {
318
            LOGGER.debug("Clossing connection "+connection.hashCode());
319
            try {
320
                connection.close();
321
            } catch(Exception ex) {
322
                LOGGER.warn("Can't close connection.", ex);
323
            }
324
       }
325
    }
326

    
327
    public void closeConnectionQuietly(Connection connection) {
328
        if( connection != null ) {
329
            LOGGER.debug("Clossing connection quietly "+connection.hashCode());
330
            try {
331
                connection.close();
332
            } catch(Exception ex) {
333
                LOGGER.warn("Can't close connection.", ex);
334
            }
335
       }
336
    }
337
    
338
    @Override
339
    protected void doDispose() throws BaseException {
340
        JDBCUtils.closeQuietly(this);
341
    }
342

    
343
    @Override
344
    public void close() throws Exception {
345
//        this.resource.removeConsumer(this);
346
        JDBCUtils.closeQuietly(this.resulSetControler);
347
//        this.resource = null;
348
        this.resulSetControler = null;
349
    }
350

    
351
    @Override
352
    public boolean closeResourceRequested(ResourceProvider resource) {
353
        return this.helperClient.closeResourceRequested(resource);
354
    }
355

    
356
    @Override
357
    public void resourceChanged(ResourceProvider resource) {
358
        this.helperClient.resourceChanged(resource);
359
    }
360

    
361
    @Override
362
    public GeometryManager getGeometryManager() {
363
        if (this.geometryManager == null) {
364
            this.geometryManager = GeometryLocator.getGeometryManager();
365
        }
366
        return this.geometryManager;
367
    }
368

    
369
    @Override
370
    public ResulSetControler getResulSetControler() {
371
        if (this.resulSetControler == null) {
372
            this.resulSetControler = new ResulSetControlerBase(this);
373
        }
374
        return this.resulSetControler;
375
    }
376

    
377
    @Override
378
    public void fetchFeature(FeatureProvider feature, ResultSetEntry rs) throws DataException {
379
        fetchFeature(feature, rs.get(), rs.getColumns());
380
    }
381

    
382
    @Override
383
    public void fetchFeature(FeatureProvider feature, ResultSet rs, FeatureAttributeDescriptor[] columns) throws DataException {
384
        Object value;
385
        FeatureAttributeDescriptor column;
386
        try {
387
            for (int index = 0; index < columns.length; index++) {
388
                column = columns[index];
389
                switch (column.getType()) {
390
                    case DataTypes.GEOMETRY:
391
                        value = this.getGeometryFromColumn(rs, index + 1);
392
                        break;
393
                    default:
394
                        value = rs.getObject(index + 1);
395
                }
396
                feature.set(column.getIndex(), value);
397
            }
398
        } catch (Exception ex) {
399
            throw new JDBCCantFetchValueException(ex);
400
        }
401
    }
402

    
403
    @Override
404
    public Geometry getGeometryFromColumn(ResultSetEntry rs, int index) throws DataException {
405
        return getGeometryFromColumn(rs.get(), index);
406
    }
407

    
408
    @Override
409
    public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
410
        try {
411
            Object value;
412
            switch (this.getGeometrySupportType()) {
413
                case NATIVE:
414
                case WKB:
415
                    value = rs.getBytes(index);
416
                    if (value == null) {
417
                        return null;
418
                    }
419
                    return this.getGeometryManager().createFrom((byte[]) value);
420

    
421
                case EWKB:
422
                    value = rs.getBytes(index);
423
                    if (value == null) {
424
                        return null;
425
                    }
426
                    return this.getGeometryManager().createFrom((byte[]) value);
427
                case WKT:
428
                default:
429
                    value = rs.getString(index);
430
                    if (value == null) {
431
                        return null;
432
                    }
433
                    return this.getGeometryManager().createFrom((String) value);
434

    
435
            }
436
        } catch (Exception ex) {
437
            throw new JDBCCantFetchValueException(ex);
438
        }
439
    }
440

    
441
    @Override
442
    public FeatureProvider createFeature(FeatureType featureType) throws DataException {
443
        return this.store.getStoreServices().createDefaultFeatureProvider(featureType);
444
    }
445
    
446
    @Override
447
    public boolean useSubquery() {
448
        if( this.store == null ) {
449
            return false;
450
        }
451
        return !StringUtils.isEmpty(this.store.getParameters().getSQL());
452
    }  
453
    
454
    @Override
455
    public SRSSolver getSRSSolver() {
456
        return this.srssolver;
457
    }
458
    
459
    @Override
460
    public JDBCStoreProvider createProvider(
461
            JDBCStoreParameters parameters, 
462
            DataStoreProviderServices providerServices
463
        ) throws InitializeException {
464
        
465
        JDBCStoreProviderBase theStore = new JDBCStoreProviderBase(
466
                parameters, 
467
                providerServices, 
468
                DBHelper.newMetadataContainer(JDBCLibrary.NAME),
469
                this
470
        );
471
        this.initialize(theStore, parameters, theStore);
472
        return theStore;
473
    }
474

    
475
    @Override
476
    public JDBCServerExplorer createServerExplorer(
477
            JDBCServerExplorerParameters parameters, 
478
            DataServerExplorerProviderServices providerServices
479
        ) throws InitializeException {
480
        
481
        JDBCServerExplorer explorer = new JDBCServerExplorerBase(
482
                parameters, 
483
                providerServices, 
484
                this
485
        );
486
        this.initialize(explorer, parameters, null);
487
        return explorer;
488
    }
489

    
490
    @Override
491
    public JDBCNewStoreParameters createNewStoreParameters() {
492
        return new JDBCNewStoreParameters();
493
    }
494

    
495
    @Override
496
    public JDBCStoreParameters createOpenStoreParameters() {
497
        return new JDBCStoreParameters();
498
    }
499

    
500
    @Override
501
    public JDBCServerExplorerParameters createServerExplorerParameters() {
502
        return new JDBCServerExplorerParameters();
503
    }
504

    
505
    @Override
506
    public String getSourceId(JDBCStoreParameters parameters) {
507
        return parameters.getHost() + ":" +
508
               parameters.getDBName() + ":" + 
509
               parameters.getSchema()+ ":" + 
510
               parameters.tableID();
511
    }
512
    
513
}