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

History | View | Annotate | Download (19.1 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.EditableFeatureType;
25
import org.gvsig.fmap.dal.feature.FeatureQuery;
26
import org.gvsig.fmap.dal.feature.FeatureRule;
27
import org.gvsig.fmap.dal.feature.FeatureRules;
28
import org.gvsig.fmap.dal.feature.FeatureType;
29
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
30
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
31
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
32
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
33
import org.gvsig.fmap.dal.resource.ResourceParameters;
34
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
35
import org.gvsig.fmap.dal.resource.exception.ResourceException;
36
import org.gvsig.fmap.dal.resource.spi.AbstractResource;
37
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
38
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
39
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
40
//import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorerBase;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
42
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
43
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
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.impl.JDBCSetProvider;
48
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.AppendOperation;
49
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CalculateEnvelopeOfColumnOperation;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanModifyTableOperation;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CountOperation;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureProviderByReferenceOperation;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.PerformChangesOperation;
55
import org.gvsig.fmap.geom.primitive.Envelope;
56
import org.gvsig.tools.dynobject.DynObject;
57
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
58
import org.gvsig.tools.exception.BaseException;
59
import org.slf4j.Logger;
60
import org.slf4j.LoggerFactory;
61

    
62
public class JDBCStoreProviderBase
63
        extends AbstractFeatureStoreProvider
64
        implements ResourceConsumer, JDBCStoreProvider {
65

    
66
    final static private Logger logger = LoggerFactory.getLogger(JDBCStoreProviderBase.class);
67

    
68
    public class CountValue implements CalculatedValue<Long> {
69
        
70
        private Long value = null;
71

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

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

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

    
190
    protected CalculatedValue<Long> count = null;
191
    
192
    protected CalculatedValue<Envelope> envelope = null;
193

    
194
    protected CalculatedValue<Boolean> allowWrite = null;
195

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

    
227
    
228
    @Override
229
    public JDBCSQLBuilderBase createExpression() {
230
        return this.getHelper().createSQLBuilder();
231
    }
232

    
233
    @Override
234
    public JDBCStoreParameters getParameters() {
235
        return (JDBCStoreParameters) super.getParameters();
236
    }  
237

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

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

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

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

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

    
329
    @Override
330
    public void close() throws CloseException {
331
        JDBCUtils.closeQuietly(this.getHelper());
332
    }
333

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

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

    
359
            return manager.openServerExplorer(exParams.getExplorerName(), exParams);
360
        } catch (Exception e) {
361
            throw new ReadException(this.getProviderName(), e);
362
        }
363
    }
364

    
365
    @Override
366
    protected void doDispose() throws BaseException {
367
        this.close();
368
        this.getHelper().dispose();
369
        super.doDispose();
370
    }
371

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

    
381
    @Override
382
    public String getName() {
383
        return this.getParameters().getTable();
384
    }
385

    
386
    @Override
387
    public String getFullName() {
388
        return this.getHelper().getSourceId(this.getParameters());
389
    }
390

    
391
    private static class DummyResource extends AbstractResource {
392

    
393
        private final String name;
394

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

    
406
        @Override
407
        public Object get() throws AccessResourceException {
408
            return null;
409
        }
410

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

    
432
    @Override
433
    public void open() throws OpenException {
434

    
435
    }
436

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

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

    
472
        FeatureType defaultType = type.getNotEditableCopy();
473
        List<FeatureType> types = Collections.singletonList(defaultType);
474
        this.getStoreServices().setFeatureTypes(types, defaultType);
475
    }
476
    
477
    @Override
478
    protected FeatureProvider internalGetFeatureProviderByReference(
479
            FeatureReferenceProviderServices reference, 
480
            FeatureType featureType
481
        ) throws DataException {
482
        JDBCStoreParameters params = this.getParameters();
483
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference = 
484
            this.getOperations().createFetchFeatureProviderByReference(
485
                reference, 
486
                featureType, 
487
                params.getDBName(),
488
                params.getSchema(), 
489
                params.getTable()
490
            );
491
        FeatureProvider feature = (FeatureProvider) fetchFeatureProviderByReference.perform();
492
        return feature;
493
    }
494
    
495
    @Override
496
    public Envelope getEnvelope() throws DataException {
497
        return this.getEnvelopeValue().get();
498
    }
499

    
500
    @Override
501
    public void performChanges(Iterator deleteds, Iterator inserteds,
502
                    Iterator updateds, Iterator featureTypesChanged)
503
                    throws DataException {
504

    
505
        FeatureType type = this.getFeatureStore().getDefaultFeatureType();
506
        JDBCStoreParameters params = this.getParameters();
507
        PerformChangesOperation performChanges = this.getOperations().createPerformChanges(
508
                params.getDBName(),
509
                params.getSchema(), 
510
                params.getTable(), 
511
                type, 
512
                deleteds, 
513
                inserteds, 
514
                updateds, 
515
                featureTypesChanged
516
        );
517
        performChanges.perform();
518
        if( performChanges.isTypeChanged() ) {
519
            // Get rules before initializing feature type
520
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
521

    
522
             // This initialization loses the feature type rules
523
            this.initializeFeatureType();
524

    
525
            // Get new feature type, clear rules and add the ones saved previously
526
            FeatureType featureType = getFeatureStore().getDefaultFeatureType();
527
            FeatureRules rules = featureType.getRules();
528
            rules.clear();
529
            for (FeatureRule rule : saved_rules) {
530
                rules.add(rule);
531
            }
532
        }
533
        this.getCountValue().reset();
534
        this.getEnvelopeValue().reset();
535
    }    
536
    
537
    @Override
538
    public boolean supportsAppendMode() {
539
        return true;
540
    }
541

    
542
    protected AppendOperation getAppendOperation() throws DataException {
543
        if( this.appendOperation == null ) {
544
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
545
            JDBCStoreParameters params = this.getParameters();
546
            this.appendOperation = this.getOperations().createAppend(
547
                params.getDBName(),
548
                params.getSchema(), 
549
                params.getTable(), 
550
                type 
551
            );
552
        }
553
        return this.appendOperation;
554
    }
555
    
556
    @Override
557
    public void endAppend() throws DataException {
558
        this.getAppendOperation().end();
559
    }
560

    
561
    @Override
562
    public void abortAppend() throws DataException {
563
        this.getAppendOperation().abort();
564
    }
565
    
566
    @Override
567
    public void beginAppend() throws DataException {
568
        this.getAppendOperation().begin();
569
    }
570

    
571
    @Override
572
    public void append(final FeatureProvider featureProvider) throws DataException {
573
        this.getAppendOperation().append(featureProvider);
574
    }    
575
    
576
    @Override
577
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
578
            throws DataException {
579
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
580
    }
581
}