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 / JDBCStoreProviderBase.java @ 43420

History | View | Annotate | Download (19.8 KB)

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

    
3
import java.text.MessageFormat;
4
import org.gvsig.fmap.dal.store.jdbc2.JDBCStoreProvider;
5
import java.util.Arrays;
6
import java.util.Collections;
7
import java.util.Iterator;
8
import java.util.List;
9
import java.util.logging.Level;
10
import org.apache.commons.lang3.BooleanUtils;
11
import org.apache.commons.lang3.StringUtils;
12
import org.cresques.cts.IProjection;
13
import org.gvsig.fmap.dal.DALLocator;
14
import org.gvsig.fmap.dal.DataManager;
15
import org.gvsig.fmap.dal.DataServerExplorer;
16
import org.gvsig.fmap.dal.DataStore;
17
import org.gvsig.fmap.dal.DataStoreNotification;
18
import org.gvsig.fmap.dal.DataTypes;
19
import org.gvsig.fmap.dal.exception.CloseException;
20
import org.gvsig.fmap.dal.exception.DataException;
21
import org.gvsig.fmap.dal.exception.InitializeException;
22
import org.gvsig.fmap.dal.exception.OpenException;
23
import org.gvsig.fmap.dal.exception.ReadException;
24
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
25
import org.gvsig.fmap.dal.feature.EditableFeatureType;
26
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
27
import org.gvsig.fmap.dal.feature.FeatureQuery;
28
import org.gvsig.fmap.dal.feature.FeatureRule;
29
import org.gvsig.fmap.dal.feature.FeatureRules;
30
import org.gvsig.fmap.dal.feature.FeatureType;
31
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
32
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
33
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
34
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
35
import org.gvsig.fmap.dal.resource.ResourceParameters;
36
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
37
import org.gvsig.fmap.dal.resource.exception.ResourceException;
38
import org.gvsig.fmap.dal.resource.spi.AbstractResource;
39
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
40
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
41
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
42
//import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorerBase;
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.jdbc2.JDBCHelper;
46
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
47
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
48
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
49
import org.gvsig.fmap.dal.store.jdbc2.impl.JDBCSetProvider;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.AppendOperation;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CalculateEnvelopeOfColumnOperation;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanModifyTableOperation;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CountOperation;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureProviderByReferenceOperation;
55
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
56
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.PerformChangesOperation;
57
import org.gvsig.fmap.geom.Geometry;
58
import org.gvsig.fmap.geom.primitive.Envelope;
59
import org.gvsig.tools.dynobject.DynObject;
60
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
61
import org.gvsig.tools.exception.BaseException;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64

    
65
public class JDBCStoreProviderBase
66
        extends AbstractFeatureStoreProvider
67
        implements ResourceConsumer, JDBCStoreProvider {
68

    
69
    final static private Logger logger = LoggerFactory.getLogger(JDBCStoreProviderBase.class);
70

    
71
    public class CountValue implements CalculatedValue<Long> {
72
        
73
        private Long value = null;
74

    
75
        @Override
76
        public void calculate() {
77
            JDBCStoreParameters params = getParameters();
78
            CountOperation count = getOperations().createCount(
79
                    params.getDBName(),
80
                    params.getSchema(),
81
                    params.getTable(),
82
                    params.getSQL(),
83
                    params.getBaseFilter(), 
84
                    null
85
            );
86
            this.value = (Long) count.perform();            
87
        }
88
        
89
        @Override
90
        public void reset() {
91
            this.value = null;
92
        }
93
        
94
        @Override
95
        public Long get() {
96
            if( this.value == null ) {
97
                this.calculate();
98
            }
99
            return this.value;
100
        }
101
    } 
102
    
103
    public class EnvelopeValue implements CalculatedValue<Envelope> {
104
        
105
        private Envelope value = null;
106
        private boolean needCalculate = true;
107

    
108
        @Override
109
        public void calculate() {
110
            try {
111
                value = null;
112
                String columnName = getFeatureStore()
113
                        .getDefaultFeatureType()
114
                        .getDefaultGeometryAttributeName();
115
                if( columnName==null ) {
116
                    return;
117
                }
118
                IProjection crs = getFeatureStore()
119
                        .getDefaultFeatureType()
120
                        .getDefaultSRS();
121
                JDBCStoreParameters params = getParameters();
122
                CalculateEnvelopeOfColumnOperation calculateEnvelopeOfColumn = 
123
                    getOperations().createCalculateEnvelopeOfColumn(
124
                        params.getSQL(), 
125
                        params.getDBName(),
126
                        params.getSchema(), 
127
                        params.getTable(), 
128
                        columnName, 
129
                        params.getBaseFilter(), 
130
                        params.getWorkingArea(), 
131
                        crs
132
                    );
133
                value = (Envelope) calculateEnvelopeOfColumn.perform();
134
                
135
            } catch(Exception ex) {
136
                throw new RuntimeException("Can't calculate envelope.", ex);
137
            } finally {
138
               needCalculate = false;
139
            }
140
        }
141
        
142
        @Override
143
        public void reset() {
144
            this.value = null;
145
            this.needCalculate = true;
146
        }
147
        
148
        @Override
149
        public synchronized Envelope get() {
150
            if( needCalculate ) {
151
                this.calculate();
152
            }
153
            return this.value;
154
        }
155
    } 
156
        
157
    public class AllowWriteValue implements CalculatedValue<Boolean> {
158
        
159
        private Boolean value = null;
160

    
161
        @Override
162
        public void calculate() {
163
            try {
164
                JDBCStoreParameters params = getParameters();
165
                CanModifyTableOperation canModifyTable = 
166
                    getOperations().createCanModifyTableOperation(
167
                        params.getDBName(),
168
                        params.getSchema(), 
169
                        params.getTable()
170
                    );
171
                this.value = (boolean) canModifyTable.perform();
172
            } catch(Exception ex) {
173
                throw new RuntimeException("Can't determine if allow write.", ex);
174
            }
175
        }
176
        
177
        @Override
178
        public void reset() {
179
            this.value = null;
180
        }
181
        
182
        @Override
183
        public Boolean get() {
184
            if( this.value == null ) {
185
                this.calculate();
186
            }
187
            return this.value;
188
        }
189
    } 
190
    
191
    protected final JDBCHelper helper;
192

    
193
    protected CalculatedValue<Long> count = null;
194
    
195
    protected CalculatedValue<Envelope> envelope = null;
196

    
197
    protected CalculatedValue<Boolean> allowWrite = null;
198

    
199
    protected AppendOperation appendOperation = null;
200
    
201
    protected JDBCStoreProviderBase(
202
            JDBCStoreParameters params,
203
            DataStoreProviderServices storeServices,
204
            DynObject metadata,
205
            JDBCHelper helper
206
    ) throws InitializeException {
207
        super(params, storeServices, metadata);
208
        this.helper = helper;
209
        this.initializeFeatureType();
210
        try {
211
            if( BooleanUtils.isTrue((Boolean) params.getDynValue("precalculateEnvelope"))  ) {
212
                FeatureType featureType = this.getStoreServices().getDefaultFeatureType();
213
                if( !StringUtils.isEmpty(featureType.getDefaultGeometryAttributeName()) ) {
214
                    Thread thread = new Thread(new Runnable() {
215
                        @Override
216
                        public void run() {
217
                            logger.debug("Precalculating envelope of '"+getSourceId()+"'.");
218
                            getEnvelopeValue().get();
219
                        }
220
                    }, "PrecalculateEnvelopeOfDBTable");
221
                    thread.start();
222
                    Thread.sleep(1);
223
                }
224
           }
225
        } catch(Exception ex) {
226
            logger.warn("Probems precalculating the envelope of table '"+this.getSourceId()+"'.", ex);
227
        }
228
    }
229

    
230
    
231
    @Override
232
    public JDBCSQLBuilderBase createExpression() {
233
        return this.getHelper().createSQLBuilder();
234
    }
235

    
236
    @Override
237
    public JDBCStoreParameters getParameters() {
238
        return (JDBCStoreParameters) super.getParameters();
239
    }  
240

    
241
    @Override
242
    public JDBCHelper getHelper() {
243
        return helper;
244
    }
245
    
246
    public OperationsFactory getOperations() {
247
        return this.getHelper().getOperations();
248
    }
249
    
250
    @Override
251
    public String getProviderName() {
252
        return this.getHelper().getProviderName();
253
    }
254
    
255
    @Override
256
    public int getOIDType() {
257
        return DataTypes.UNKNOWN;
258
    }
259

    
260
    @Override
261
    public Object createNewOID() {
262
        return null;
263
    }
264
    
265
    @Override
266
    public boolean allowAutomaticValues() {
267
        return this.getHelper().allowAutomaticValues();
268
    }
269

    
270
    @Override
271
    public boolean allowWrite() {
272
        return this.getAllowWriteValue().get();
273
    }
274
    
275
    @Override
276
    public Object getDynValue(String name) throws DynFieldNotFoundException {
277
        try {
278
            if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
279
                Envelope env = this.getEnvelope();
280
                if (env != null) {
281
                    return env;
282
                }
283
            } else if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
284
                IProjection proj;
285
                proj = this.getFeatureStore().getDefaultFeatureType().getDefaultSRS();
286
                if (proj != null) {
287
                    return proj;
288
                }
289
            }
290
        } catch (DataException e) {
291
            throw new RuntimeException(e);
292
        }
293
        return super.getDynValue(name);
294
    }
295

    
296
    @Override
297
    public CalculatedValue<Long> getCountValue() {
298
        if( this.count == null ) {
299
            this.count = new CountValue();
300
        }
301
        return this.count;
302
    }
303

    
304
    @Override
305
    public CalculatedValue<Envelope> getEnvelopeValue() {
306
        if( this.envelope == null ) {
307
            this.envelope = new EnvelopeValue();
308
        }
309
        return this.envelope;
310
    }
311
    
312
    @Override
313
    public CalculatedValue<Boolean> getAllowWriteValue() {
314
        if( this.allowWrite == null ) {
315
            this.allowWrite = new AllowWriteValue();
316
        }
317
        return this.allowWrite;
318
    }
319
    
320
    @Override
321
    public long getFeatureCount() throws DataException {
322
        return this.getCountValue().get();
323
    }
324
    
325
    @Override
326
    public boolean closeResourceRequested(ResourceProvider resource) {
327
        ResulSetControler resulSetControler = this.getHelper().getResulSetControler();
328
        resulSetControler.pack();
329
        return resulSetControler.getOpenCount() == 0;
330
    }
331

    
332
    @Override
333
    public void close() throws CloseException {
334
        JDBCUtils.closeQuietly(this.getHelper());
335
    }
336

    
337
    @Override
338
    public void resourceChanged(ResourceProvider resource) {
339
        this.getStoreServices().notifyChange(
340
                DataStoreNotification.RESOURCE_CHANGED,
341
                resource
342
        );
343
    }
344

    
345
    @Override
346
    public DataServerExplorer getExplorer() throws ReadException {
347
        DataManager manager = DALLocator.getDataManager();
348
        JDBCServerExplorerParameters exParams;
349
        JDBCStoreParameters params = getParameters();
350
        try {
351
            exParams = this.getHelper().createServerExplorerParameters();
352
            exParams.setHost(params.getHost());
353
            exParams.setPort(params.getPort());
354
            exParams.setDBName(params.getDBName());
355
            exParams.setUser(params.getUser());
356
            exParams.setPassword(params.getPassword());
357
            exParams.setUrl(params.getUrl());
358
            exParams.setCatalog(params.getCatalog());
359
            exParams.setSchema(params.getSchema());
360
            exParams.setJDBCDriverClassName(params.getJDBCDriverClassName());
361

    
362
            return manager.openServerExplorer(exParams.getExplorerName(), exParams);
363
        } catch (Exception e) {
364
            throw new ReadException(this.getProviderName(), e);
365
        }
366
    }
367

    
368
    @Override
369
    protected void doDispose() throws BaseException {
370
        this.close();
371
        this.getHelper().dispose();
372
        super.doDispose();
373
    }
374

    
375
    @Override
376
    public String getSourceId() {
377
        try {
378
            return this.getHelper().getSourceId(this.getParameters());
379
        } catch(Exception ex) {
380
            return "unknow";
381
        }
382
    }
383

    
384
    @Override
385
    public String getName() {
386
        return this.getParameters().getTable();
387
    }
388

    
389
    @Override
390
    public String getFullName() {
391
        return this.getHelper().getSourceId(this.getParameters());
392
    }
393

    
394
    private static class DummyResource extends AbstractResource {
395

    
396
        private final String name;
397

    
398
        DummyResource(String name) throws InitializeException {
399
            super((ResourceParameters)null);
400
            this.name = name;
401
        }
402
        
403
        @Override
404
        public String getName() throws AccessResourceException {
405
            return MessageFormat.format("DummyResource({0})",
406
                                new Object[] { this.name });
407
        }
408

    
409
        @Override
410
        public Object get() throws AccessResourceException {
411
            return null;
412
        }
413

    
414
        @Override
415
        public boolean isThis(ResourceParameters parameters) throws ResourceException {
416
            return true;
417
        }
418
        
419
    }
420
    
421
    @Override
422
    public ResourceProvider getResource() {
423
        ResourceProvider r = getHelper().getResource();
424
        if( r == null ) {
425
            try {
426
                r = new DummyResource(this.getName());
427
            } catch (InitializeException ex) {
428
                logger.warn("Can't create DummyResource",ex);
429
                // Do nothing
430
            }
431
        }
432
        return r;
433
    }
434

    
435
    @Override
436
    public void open() throws OpenException {
437

    
438
    }
439

    
440
    @Override
441
    public FeatureSetProvider createSet(
442
            FeatureQuery query,
443
            FeatureType featureType
444
        ) throws DataException {
445
        
446
        FeatureSetProvider set = new JDBCSetProvider(
447
                this,
448
                this.getHelper(), 
449
                query, 
450
                featureType
451
        );
452
        
453
        return set;
454
    }
455

    
456
    protected void initializeFeatureType() {
457
        EditableFeatureType type = this.getStoreServices().createFeatureType(getName());
458
        JDBCStoreParameters params = this.getParameters();
459
        List<String> primaryKeys = null;
460
        if( params.getPkFields() != null ) {
461
            primaryKeys = Arrays.asList(params.getPkFields());
462
        }
463
        FetchFeatureTypeOperation fetchFeatureType = 
464
             this.getOperations().createFetchFeatureType(
465
                type,
466
                params.getDBName(),
467
                params.getSchema(),
468
                params.getTable(),
469
                primaryKeys,
470
                params.getDefaultGeometryField(),
471
                params.getCRS()
472
            );
473
        fetchFeatureType.perform();
474

    
475
        if( !StringUtils.isEmpty(params.getDefaultGeometryField()) ) {
476
            if( !params.getDefaultGeometryField().equalsIgnoreCase(type.getDefaultGeometryAttributeName()) ) {
477
                type.setDefaultGeometryAttributeName(params.getDefaultGeometryField());
478
                EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) type.getDefaultGeometryAttribute();
479
                attr.setGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
480
            }
481
        }
482
        FeatureType defaultType = type.getNotEditableCopy();
483
        List<FeatureType> types = Collections.singletonList(defaultType);
484
        this.getStoreServices().setFeatureTypes(types, defaultType);
485
    }
486
    
487
    @Override
488
    protected FeatureProvider internalGetFeatureProviderByReference(
489
            FeatureReferenceProviderServices reference, 
490
            FeatureType featureType
491
        ) throws DataException {
492
        JDBCStoreParameters params = this.getParameters();
493
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference = 
494
            this.getOperations().createFetchFeatureProviderByReference(
495
                reference, 
496
                featureType, 
497
                params.getDBName(),
498
                params.getSchema(), 
499
                params.getTable()
500
            );
501
        FeatureProvider feature = (FeatureProvider) fetchFeatureProviderByReference.perform();
502
        return feature;
503
    }
504
    
505
    @Override
506
    public Envelope getEnvelope() throws DataException {
507
        return this.getEnvelopeValue().get();
508
    }
509

    
510
    @Override
511
    public void performChanges(Iterator deleteds, Iterator inserteds,
512
                    Iterator updateds, Iterator featureTypesChanged)
513
                    throws DataException {
514

    
515
        FeatureType type = this.getFeatureStore().getDefaultFeatureType();
516
        JDBCStoreParameters params = this.getParameters();
517
        PerformChangesOperation performChanges = this.getOperations().createPerformChanges(
518
                params.getDBName(),
519
                params.getSchema(), 
520
                params.getTable(), 
521
                type, 
522
                deleteds, 
523
                inserteds, 
524
                updateds, 
525
                featureTypesChanged
526
        );
527
        performChanges.perform();
528
        if( performChanges.isTypeChanged() ) {
529
            // Get rules before initializing feature type
530
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
531

    
532
             // This initialization loses the feature type rules
533
            this.initializeFeatureType();
534

    
535
            // Get new feature type, clear rules and add the ones saved previously
536
            FeatureType featureType = getFeatureStore().getDefaultFeatureType();
537
            FeatureRules rules = featureType.getRules();
538
            rules.clear();
539
            for (FeatureRule rule : saved_rules) {
540
                rules.add(rule);
541
            }
542
        }
543
        this.getCountValue().reset();
544
        this.getEnvelopeValue().reset();
545
    }    
546
    
547
    @Override
548
    public boolean supportsAppendMode() {
549
        return true;
550
    }
551

    
552
    protected AppendOperation getAppendOperation() throws DataException {
553
        if( this.appendOperation == null ) {
554
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
555
            JDBCStoreParameters params = this.getParameters();
556
            this.appendOperation = this.getOperations().createAppend(
557
                params.getDBName(),
558
                params.getSchema(), 
559
                params.getTable(), 
560
                type 
561
            );
562
        }
563
        return this.appendOperation;
564
    }
565
    
566
    @Override
567
    public void endAppend() throws DataException {
568
        this.getAppendOperation().end();
569
    }
570

    
571
    @Override
572
    public void abortAppend() throws DataException {
573
        this.getAppendOperation().abort();
574
    }
575
    
576
    @Override
577
    public void beginAppend() throws DataException {
578
        this.getAppendOperation().begin();
579
    }
580

    
581
    @Override
582
    public void append(final FeatureProvider featureProvider) throws DataException {
583
        this.getAppendOperation().append(featureProvider);
584
    }    
585
    
586
    @Override
587
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
588
            throws DataException {
589
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
590
    }
591
}