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

History | View | Annotate | Download (19.3 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 org.apache.commons.lang3.BooleanUtils;
10
import org.apache.commons.lang3.StringUtils;
11
import org.cresques.cts.IProjection;
12
import org.gvsig.fmap.dal.DALLocator;
13
import org.gvsig.fmap.dal.DataManager;
14
import org.gvsig.fmap.dal.DataServerExplorer;
15
import org.gvsig.fmap.dal.DataStore;
16
import org.gvsig.fmap.dal.DataStoreNotification;
17
import org.gvsig.fmap.dal.DataTypes;
18
import org.gvsig.fmap.dal.exception.CloseException;
19
import org.gvsig.fmap.dal.exception.DataException;
20
import org.gvsig.fmap.dal.exception.InitializeException;
21
import org.gvsig.fmap.dal.exception.OpenException;
22
import org.gvsig.fmap.dal.exception.ReadException;
23
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
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.jdbc.JDBCServerExplorerParameters;
41
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
42
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
43
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
44
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
45
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
46
import org.gvsig.fmap.dal.store.jdbc2.impl.JDBCSetProvider;
47
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.AppendOperation;
48
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CalculateEnvelopeOfColumnOperation;
49
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanModifyTableOperation;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CountOperation;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureProviderByReferenceOperation;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.PerformChangesOperation;
54
import org.gvsig.fmap.geom.Geometry;
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
@SuppressWarnings("UseSpecificCatch")
63
public class JDBCStoreProviderBase
64
        extends AbstractFeatureStoreProvider
65
        implements ResourceConsumer, JDBCStoreProvider {
66

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

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

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

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

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

    
183
    protected CalculatedValue<Long> count = null;
184
    
185
    protected CalculatedValue<Envelope> envelope = null;
186

    
187
    protected CalculatedValue<Boolean> allowWrite = null;
188

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

    
221
    
222
    @Override
223
    public JDBCSQLBuilderBase createExpression() {
224
        return this.getHelper().createSQLBuilder();
225
    }
226

    
227
    @Override
228
    public JDBCStoreParameters getParameters() {
229
        return (JDBCStoreParameters) super.getParameters();
230
    }  
231

    
232
    @Override
233
    public JDBCHelper getHelper() {
234
        return helper;
235
    }
236
    
237
    public OperationsFactory getOperations() {
238
        return this.getHelper().getOperations();
239
    }
240
    
241
    @Override
242
    public String getProviderName() {
243
        return this.getHelper().getProviderName();
244
    }
245
    
246
    @Override
247
    public int getOIDType() {
248
        return DataTypes.UNKNOWN;
249
    }
250

    
251
    @Override
252
    public Object createNewOID() {
253
        return null;
254
    }
255
    
256
    @Override
257
    public boolean allowAutomaticValues() {
258
        return this.getHelper().allowAutomaticValues();
259
    }
260

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

    
287
    @Override
288
    public CalculatedValue<Long> getCountValue() {
289
        if( this.count == null ) {
290
            this.count = new CountValue();
291
        }
292
        return this.count;
293
    }
294

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

    
323
    @Override
324
    public void close() throws CloseException {
325
        JDBCUtils.closeQuietly(this.getHelper());
326
    }
327

    
328
    @Override
329
    public void resourceChanged(ResourceProvider resource) {
330
        this.getStoreServices().notifyChange(
331
                DataStoreNotification.RESOURCE_CHANGED,
332
                resource
333
        );
334
    }
335

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

    
353
            return manager.openServerExplorer(exParams.getExplorerName(), exParams);
354
        } catch (Exception e) {
355
            throw new ReadException(this.getProviderName(), e);
356
        }
357
    }
358

    
359
    @Override
360
    protected void doDispose() throws BaseException {
361
        this.close();
362
        this.getHelper().dispose();
363
        super.doDispose();
364
    }
365

    
366
    @Override
367
    public String getSourceId() {
368
        try {
369
            return this.getHelper().getSourceId(this.getParameters());
370
        } catch(Exception ex) {
371
            return "unknow";
372
        }
373
    }
374

    
375
    @Override
376
    public String getName() {
377
        return this.getParameters().getTable();
378
    }
379

    
380
    @Override
381
    public String getFullName() {
382
        return this.getHelper().getSourceId(this.getParameters());
383
    }
384

    
385
    private static class DummyResource extends AbstractResource {
386

    
387
        private final String name;
388

    
389
        DummyResource(String name) throws InitializeException {
390
            super((ResourceParameters)null);
391
            this.name = name;
392
        }
393
        
394
        @Override
395
        public String getName() throws AccessResourceException {
396
            return MessageFormat.format("DummyResource({0})",
397
                                new Object[] { this.name });
398
        }
399

    
400
        @Override
401
        public Object get() throws AccessResourceException {
402
            return null;
403
        }
404

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

    
426
    @Override
427
    public void open() throws OpenException {
428

    
429
    }
430

    
431
    @Override
432
    public FeatureSetProvider createSet(
433
            FeatureQuery query,
434
            FeatureType featureType
435
        ) throws DataException {
436
        
437
        FeatureSetProvider set = new JDBCSetProvider(
438
                this,
439
                this.getHelper(), 
440
                query, 
441
                featureType
442
        );
443
        
444
        return set;
445
    }
446

    
447
    protected void initializeFeatureType() {
448
        EditableFeatureType type = this.getStoreServices().createFeatureType(getName());
449
        JDBCStoreParameters params = this.getParameters();
450
        List<String> primaryKeys = null;
451
        if( params.getPkFields() != null ) {
452
            primaryKeys = Arrays.asList(params.getPkFields());
453
        }
454
        FetchFeatureTypeOperation fetchFeatureType = 
455
             this.getOperations().createFetchFeatureType(
456
                type,
457
                this.getOperations().createTableReference(params),
458
                primaryKeys,
459
                params.getDefaultGeometryField(),
460
                params.getCRS()
461
            );
462
        fetchFeatureType.perform();
463

    
464
        if( !StringUtils.isEmpty(params.getDefaultGeometryField()) ) {
465
            if( !params.getDefaultGeometryField().equalsIgnoreCase(type.getDefaultGeometryAttributeName()) ) {
466
                type.setDefaultGeometryAttributeName(params.getDefaultGeometryField());
467
                EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) type.getDefaultGeometryAttribute();
468
                attr.setGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
469
            }
470
        }
471
        FeatureType defaultType = type.getNotEditableCopy();
472
        List<FeatureType> types = Collections.singletonList(defaultType);
473
        this.getStoreServices().setFeatureTypes(types, defaultType);
474
    }
475
    
476
    @Override
477
    protected FeatureProvider internalGetFeatureProviderByReference(
478
            FeatureReferenceProviderServices reference, 
479
            FeatureType featureType
480
        ) throws DataException {
481
        JDBCStoreParameters params = this.getParameters();
482
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference = 
483
            this.getOperations().createFetchFeatureProviderByReference(
484
                reference, 
485
                featureType, 
486
                this.getOperations().createTableReference(params)
487
            );
488
        FeatureProvider feature = (FeatureProvider) fetchFeatureProviderByReference.perform();
489
        return feature;
490
    }
491
    
492
    @Override
493
    public Envelope getEnvelope() throws DataException {
494
        return this.getEnvelopeValue().get();
495
    }
496

    
497
    @Override
498
    public void performChanges(Iterator deleteds, Iterator inserteds,
499
                    Iterator updateds, Iterator featureTypesChanged)
500
                    throws DataException {
501

    
502
        FeatureType type = this.getFeatureStore().getDefaultFeatureType();
503
        JDBCStoreParameters params = this.getParameters();
504
        PerformChangesOperation performChanges = this.getOperations().createPerformChanges(
505
                this.getOperations().createTableReference(params),
506
                type, 
507
                deleteds, 
508
                inserteds, 
509
                updateds, 
510
                featureTypesChanged
511
        );
512
        performChanges.perform();
513
        if( performChanges.isTypeChanged() ) {
514
            // Get rules before initializing feature type
515
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
516

    
517
             // This initialization loses the feature type rules
518
            this.initializeFeatureType();
519

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

    
537
    protected AppendOperation getAppendOperation() throws DataException {
538
        if( this.appendOperation == null ) {
539
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
540
            JDBCStoreParameters params = this.getParameters();
541
            this.appendOperation = this.getOperations().createAppend(
542
                this.getOperations().createTableReference(params),
543
                type 
544
            );
545
        }
546
        return this.appendOperation;
547
    }
548
    
549
    @Override
550
    public void endAppend() throws DataException {
551
        this.getAppendOperation().end();
552
    }
553

    
554
    @Override
555
    public void abortAppend() throws DataException {
556
        this.getAppendOperation().abort();
557
    }
558
    
559
    @Override
560
    public void beginAppend() throws DataException {
561
        this.getAppendOperation().begin();
562
    }
563

    
564
    @Override
565
    public void append(final FeatureProvider featureProvider) throws DataException {
566
        this.getAppendOperation().append(featureProvider);
567
    }    
568
    
569
    @Override
570
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
571
            throws DataException {
572
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
573
    }
574
}