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

History | View | Annotate | Download (18.8 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.expressionevaluator.SymbolTable;
19
import org.gvsig.fmap.dal.DataTypes;
20
import org.gvsig.fmap.dal.exception.DataException;
21
import org.gvsig.fmap.dal.exception.InitializeException;
22
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
23
import org.gvsig.fmap.dal.feature.FeatureQueryOrder;
24
import org.gvsig.fmap.dal.feature.FeatureStore;
25
import org.gvsig.fmap.dal.feature.FeatureType;
26

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

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

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

    
67
    private static final Logger LOGGER = LoggerFactory.getLogger(JDBCHelperBase.class);
68

    
69
    private ResulSetControler resulSetControler = null;
70

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

    
75
    private GeometryManager geometryManager = null;
76

    
77
    private JDBCConnectionParameters connectionParameters;
78

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

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

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

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

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

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

    
142
    @Override
143
    public String getQuoteForIdentifiers() {
144
        return QUOTE_FOR_USE_IN_IDENTIFIERS;
145
    }
146

    
147
    @Override
148
    public boolean allowAutomaticValues() {
149
        return ALLOW_AUTOMATIC_VALUES;
150
    }
151

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

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

    
192
        // Ahora vamos a comprobar que las funciones que se usan son 
193
        // compatibles sql, y que no se usan funciones OGC si el 
194
        // proveedor dice que no soporta funciones espaciales.
195
        // Tambien comprobaremos que el filtro no usa ningun campo calculado.
196
        final MutableBoolean isCompatible = new MutableBoolean(true);
197
        final boolean supportSpatialFunctions = this.hasSpatialFunctions();
198
        ExpressionEvaluatorManager manager = ExpressionEvaluatorLocator.getManager();
199
        Code code = manager.compile(sql);
200
        SymbolTable symbolTable = manager.createSymbolTable();
201
        code.link(symbolTable);
202
        try {
203
            code.accept(new Visitor() {
204
                @Override
205
                public void visit(Object code_obj) throws VisitCanceledException, BaseException {
206
                    Code code = (Code) code_obj;
207
                    switch(code.code()) {
208
                        case Code.CALLER:
209
                            Code.Caller caller = (Code.Caller) code;
210
                            Function function = caller.function();
211
                            if( function==null ) {
212
                                isCompatible.setValue(false);
213
                                throw new VisitCanceledException();
214
                            }
215
                            if( !function.isSQLCompatible() ) {
216
                                isCompatible.setValue(false);
217
                                throw new VisitCanceledException();
218
                            }
219
                            if( !supportSpatialFunctions ) {
220
                                if( StringUtils.equalsIgnoreCase(function.group(),Function.GROUP_OGC) ) {
221
                                    isCompatible.setValue(false);
222
                                    throw new VisitCanceledException();
223
                                }
224
                            }
225
                            break;
226
                            
227
                        case Code.IDENTIFIER:
228
                            Code.Identifier identifier = (Code.Identifier) code;
229
                            if( type!=null ) {
230
                                FeatureAttributeDescriptor attrdesc = type.getAttributeDescriptor(identifier.name());
231
                                if( attrdesc!=null ) {
232
                                    if( attrdesc.isComputed() ) {
233
                                        isCompatible.setValue(false);
234
                                        throw new VisitCanceledException();
235
                                    }
236
                                }
237
                            }
238
                            break;
239
                    }
240
                }
241
            });
242

    
243
        } catch (VisitCanceledException ex) {
244
            // Do nothing
245
        } catch (Exception ex) {
246
            LOGGER.warn("Can't calculate if is SQL compatible.", ex);
247
        }
248
        
249
        return isCompatible.booleanValue();
250
    }
251
    
252
    @Override
253
    public boolean supportOrder(FeatureType type, FeatureQueryOrder order) {
254
        if (this.useSubquery()) {
255
            return false;
256
        }
257
        if (order == null) {
258
            return true;
259
        }
260
        for( FeatureQueryOrder.FeatureQueryOrderMember member : order.members() ) {
261
            if (member.hasEvaluator()) {
262
                if( !this.supportFilter(type, member.getEvaluator()) ) {
263
                    return false;
264
                }
265
            }            
266
        }
267
        return true;
268
    }
269
    
270
    @Override
271
    public OperationsFactory getOperations() {
272
        if (this.operationsFactory== null) {
273
            this.operationsFactory = new OperationsFactoryBase(this);
274
        }
275
        return operationsFactory;
276
    }
277
    
278
    protected void initializeResource(JDBCConnectionParameters params) {
279
//        Object[] resourceParams = new Object[]{
280
//            params.getUrl(),
281
//            params.getHost(),
282
//            params.getPort(),
283
//            params.getDBName(),
284
//            params.getUser(),
285
//            params.getPassword(),
286
//            params.getJDBCDriverClassName()
287
//        };
288
//
289
//        try {
290
//            ResourceManagerProviderServices manager
291
//                    = (ResourceManagerProviderServices) DALLocator.getResourceManager();
292
//            JDBCResource resource = (JDBCResource) manager.createAddResource(
293
//                    this.getResourceType(),
294
//                    resourceParams
295
//            );
296
//            this.resource = resource;
297
//            this.resource.addConsumer(this);
298
//        } catch (InitializeException ex) {
299
//            logger.debug("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
300
//            throw new RuntimeException("Can't initialize resource (" + ArrayUtils.toString(resourceParams) + ").", ex);
301
//        }
302

    
303
    }
304

    
305
    @Override
306
    public String getSourceId() {
307
        return this.store.getSourceId();
308
    }
309
    
310
    @Override
311
    public JDBCResource getResource() {
312
        return null;
313
//        return this.resource;
314
    }
315

    
316
    @Override
317
    public Connection getConnection() throws AccessResourceException {
318
        throw new NotYetImplemented();
319
    }
320

    
321
    @Override
322
    public Connection getConnectionWritable() throws AccessResourceException {
323
        return this.getConnection();
324
    }
325

    
326
    @Override
327
    public String getConnectionURL() {
328
        return null;
329
    }
330

    
331
    @Override
332
    public JDBCConnectionParameters getConnectionParameters() {
333
        return connectionParameters;
334
    }
335

    
336
    @Override
337
    public void closeConnection(Connection connection) {
338
        if( connection != null ) {
339
            LOGGER.debug("Clossing connection "+connection.hashCode());
340
            try {
341
                connection.close();
342
            } catch(Exception ex) {
343
                LOGGER.warn("Can't close connection.", ex);
344
            }
345
       }
346
    }
347

    
348
    @Override
349
    public void closeConnectionQuietly(Connection connection) {
350
        if( connection != null ) {
351
            LOGGER.debug("Clossing connection quietly "+connection.hashCode());
352
            try {
353
                connection.close();
354
            } catch(Exception ex) {
355
                LOGGER.warn("Can't close connection.", ex);
356
            }
357
       }
358
    }
359
    
360
    @Override
361
    protected void doDispose() throws BaseException {
362
        JDBCUtils.closeQuietly(this);
363
    }
364

    
365
    @Override
366
    public void close() throws Exception {
367
//        this.resource.removeConsumer(this);
368
        JDBCUtils.closeQuietly(this.resulSetControler);
369
//        this.resource = null;
370
        this.resulSetControler = null;
371
    }
372

    
373
    @Override
374
    public boolean closeResourceRequested(ResourceProvider resource) {
375
        return this.helperClient.closeResourceRequested(resource);
376
    }
377

    
378
    @Override
379
    public void resourceChanged(ResourceProvider resource) {
380
        this.helperClient.resourceChanged(resource);
381
    }
382

    
383
    @Override
384
    public GeometryManager getGeometryManager() {
385
        if (this.geometryManager == null) {
386
            this.geometryManager = GeometryLocator.getGeometryManager();
387
        }
388
        return this.geometryManager;
389
    }
390

    
391
    @Override
392
    public ResulSetControler getResulSetControler() {
393
        if (this.resulSetControler == null) {
394
            this.resulSetControler = new ResulSetControlerBase(this);
395
        }
396
        return this.resulSetControler;
397
    }
398

    
399
    @Override
400
    public void fetchFeature(FeatureProvider feature, ResultSetEntry rs) throws DataException {
401
        fetchFeature(feature, rs.get(), rs.getColumns());
402
    }
403

    
404
    @Override
405
    public void fetchFeature(FeatureProvider feature, ResultSet rs, FeatureAttributeDescriptor[] columns) throws DataException {
406
        Object value;
407
        FeatureAttributeDescriptor column;
408
        try {
409
            for (int index = 0; index < columns.length; index++) {
410
                column = columns[index];
411
                switch (column.getType()) {
412
                    case DataTypes.GEOMETRY:
413
                        value = this.getGeometryFromColumn(rs, index + 1);
414
                        break;
415
                    default:
416
                        value = rs.getObject(index + 1);
417
                }
418
                feature.set(column.getIndex(), value);
419
            }
420
        } catch (Exception ex) {
421
            throw new JDBCCantFetchValueException(ex);
422
        }
423
    }
424

    
425
    @Override
426
    public Geometry getGeometryFromColumn(ResultSetEntry rs, int index) throws DataException {
427
        return getGeometryFromColumn(rs.get(), index);
428
    }
429

    
430
    @Override
431
    public Geometry getGeometryFromColumn(ResultSet rs, int index) throws DataException {
432
        try {
433
            Object value;
434
            switch (this.getGeometrySupportType()) {
435
                case NATIVE:
436
                case WKB:
437
                    value = rs.getBytes(index);
438
                    if (value == null) {
439
                        return null;
440
                    }
441
                    return this.getGeometryManager().createFrom((byte[]) value);
442

    
443
                case EWKB:
444
                    value = rs.getBytes(index);
445
                    if (value == null) {
446
                        return null;
447
                    }
448
                    return this.getGeometryManager().createFrom((byte[]) value);
449
                case WKT:
450
                default:
451
                    value = rs.getString(index);
452
                    if (value == null) {
453
                        return null;
454
                    }
455
                    return this.getGeometryManager().createFrom((String) value);
456

    
457
            }
458
        } catch (Exception ex) {
459
            throw new JDBCCantFetchValueException(ex);
460
        }
461
    }
462

    
463
    @Override
464
    public FeatureProvider createFeature(FeatureType featureType) throws DataException {
465
        return this.store.getStoreServices().createDefaultFeatureProvider(featureType);
466
    }
467
    
468
    @Override
469
    public boolean useSubquery() {
470
        if( this.store == null ) {
471
            return false;
472
        }
473
        return !StringUtils.isEmpty(this.store.getParameters().getSQL());
474
    }  
475
    
476
    @Override
477
    public SRSSolver getSRSSolver() {
478
        return this.srssolver;
479
    }
480
    
481
    @Override
482
    public JDBCStoreProvider createProvider(
483
            JDBCStoreParameters parameters, 
484
            DataStoreProviderServices providerServices
485
        ) throws InitializeException {
486
        
487
        JDBCStoreProviderBase theStore = new JDBCStoreProviderBase(
488
                parameters, 
489
                providerServices, 
490
                DBHelper.newMetadataContainer(JDBCLibrary.NAME),
491
                this
492
        );
493
        this.initialize(theStore, parameters, theStore);
494
        return theStore;
495
    }
496

    
497
    @Override
498
    public JDBCServerExplorer createServerExplorer(
499
            JDBCServerExplorerParameters parameters, 
500
            DataServerExplorerProviderServices providerServices
501
        ) throws InitializeException {
502
        
503
        JDBCServerExplorer explorer = new JDBCServerExplorerBase(
504
                parameters, 
505
                providerServices, 
506
                this
507
        );
508
        this.initialize(explorer, parameters, null);
509
        return explorer;
510
    }
511

    
512
    @Override
513
    public JDBCNewStoreParameters createNewStoreParameters() {
514
        return new JDBCNewStoreParameters();
515
    }
516

    
517
    @Override
518
    public JDBCStoreParameters createOpenStoreParameters() {
519
        return new JDBCStoreParameters();
520
    }
521

    
522
    @Override
523
    public JDBCServerExplorerParameters createServerExplorerParameters() {
524
        return new JDBCServerExplorerParameters();
525
    }
526

    
527
    @Override
528
    public String getSourceId(JDBCStoreParameters parameters) {
529
        return parameters.getHost() + ":" +
530
               parameters.getDBName() + ":" + 
531
               parameters.getSchema()+ ":" + 
532
               parameters.tableID();
533
    }
534

    
535
    @Override
536
    public boolean isThreadSafe() {
537
        return true;
538
    }
539
    
540
}