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

History | View | Annotate | Download (19.6 KB)

1 43020 jjdelcerro
package org.gvsig.fmap.dal.store.jdbc2.spi;
2
3 43409 jjdelcerro
import java.text.MessageFormat;
4 43020 jjdelcerro
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 43361 jjdelcerro
import org.apache.commons.lang3.BooleanUtils;
10
import org.apache.commons.lang3.StringUtils;
11 43020 jjdelcerro
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 43420 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
24 43020 jjdelcerro
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 43409 jjdelcerro
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 43020 jjdelcerro
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 43420 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
55 43020 jjdelcerro
import org.gvsig.fmap.geom.primitive.Envelope;
56 44185 jjdelcerro
import org.gvsig.tools.dynobject.DynField;
57 43020 jjdelcerro
import org.gvsig.tools.dynobject.DynObject;
58
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
59
import org.gvsig.tools.exception.BaseException;
60
import org.slf4j.Logger;
61
import org.slf4j.LoggerFactory;
62
63 44058 jjdelcerro
@SuppressWarnings("UseSpecificCatch")
64 43020 jjdelcerro
public class JDBCStoreProviderBase
65
        extends AbstractFeatureStoreProvider
66
        implements ResourceConsumer, JDBCStoreProvider {
67
68 44058 jjdelcerro
    final static private Logger LOGGER = LoggerFactory.getLogger(JDBCStoreProviderBase.class);
69 43020 jjdelcerro
70
    public class CountValue implements CalculatedValue<Long> {
71
72
        private Long value = null;
73
74
        @Override
75
        public void calculate() {
76
            JDBCStoreParameters params = getParameters();
77
            CountOperation count = getOperations().createCount(
78 44058 jjdelcerro
                    getOperations().createTableReference(params),
79 43020 jjdelcerro
                    params.getBaseFilter(),
80
                    null
81
            );
82
            this.value = (Long) count.perform();
83
        }
84
85
        @Override
86
        public void reset() {
87
            this.value = null;
88
        }
89
90
        @Override
91
        public Long get() {
92
            if( this.value == null ) {
93
                this.calculate();
94
            }
95
            return this.value;
96
        }
97
    }
98
99
    public class EnvelopeValue implements CalculatedValue<Envelope> {
100
101
        private Envelope value = null;
102 43163 jjdelcerro
        private boolean needCalculate = true;
103 43020 jjdelcerro
104
        @Override
105
        public void calculate() {
106
            try {
107 43163 jjdelcerro
                value = null;
108 43020 jjdelcerro
                String columnName = getFeatureStore()
109
                        .getDefaultFeatureType()
110
                        .getDefaultGeometryAttributeName();
111 43163 jjdelcerro
                if( columnName==null ) {
112
                    return;
113
                }
114 43020 jjdelcerro
                IProjection crs = getFeatureStore()
115
                        .getDefaultFeatureType()
116
                        .getDefaultSRS();
117
                JDBCStoreParameters params = getParameters();
118
                CalculateEnvelopeOfColumnOperation calculateEnvelopeOfColumn =
119
                    getOperations().createCalculateEnvelopeOfColumn(
120 44058 jjdelcerro
                        getOperations().createTableReference(params),
121 43020 jjdelcerro
                        columnName,
122
                        params.getBaseFilter(),
123
                        params.getWorkingArea(),
124
                        crs
125
                    );
126
                value = (Envelope) calculateEnvelopeOfColumn.perform();
127 43163 jjdelcerro
128 43020 jjdelcerro
            } catch(Exception ex) {
129
                throw new RuntimeException("Can't calculate envelope.", ex);
130 43163 jjdelcerro
            } finally {
131
               needCalculate = false;
132 43020 jjdelcerro
            }
133
        }
134
135
        @Override
136
        public void reset() {
137
            this.value = null;
138 43163 jjdelcerro
            this.needCalculate = true;
139 43020 jjdelcerro
        }
140
141
        @Override
142 43361 jjdelcerro
        public synchronized Envelope get() {
143 43163 jjdelcerro
            if( needCalculate ) {
144 43020 jjdelcerro
                this.calculate();
145
            }
146
            return this.value;
147
        }
148
    }
149 43163 jjdelcerro
150 43020 jjdelcerro
    public class AllowWriteValue implements CalculatedValue<Boolean> {
151
152
        private Boolean value = null;
153
154
        @Override
155
        public void calculate() {
156
            try {
157
                JDBCStoreParameters params = getParameters();
158
                CanModifyTableOperation canModifyTable =
159
                    getOperations().createCanModifyTableOperation(
160 44058 jjdelcerro
                        getOperations().createTableReference(params)
161 43020 jjdelcerro
                    );
162
                this.value = (boolean) canModifyTable.perform();
163
            } catch(Exception ex) {
164
                throw new RuntimeException("Can't determine if allow write.", ex);
165
            }
166
        }
167
168
        @Override
169
        public void reset() {
170
            this.value = null;
171
        }
172
173
        @Override
174
        public Boolean get() {
175
            if( this.value == null ) {
176
                this.calculate();
177
            }
178
            return this.value;
179
        }
180
    }
181
182
    protected final JDBCHelper helper;
183
184
    protected CalculatedValue<Long> count = null;
185
186
    protected CalculatedValue<Envelope> envelope = null;
187
188
    protected CalculatedValue<Boolean> allowWrite = null;
189
190
    protected AppendOperation appendOperation = null;
191
192 44058 jjdelcerro
    @SuppressWarnings({"OverridableMethodCallInConstructor", "CallToThreadStartDuringObjectConstruction"})
193 43020 jjdelcerro
    protected JDBCStoreProviderBase(
194
            JDBCStoreParameters params,
195
            DataStoreProviderServices storeServices,
196
            DynObject metadata,
197
            JDBCHelper helper
198
    ) throws InitializeException {
199
        super(params, storeServices, metadata);
200
        this.helper = helper;
201
        this.initializeFeatureType();
202 43361 jjdelcerro
        try {
203
            if( BooleanUtils.isTrue((Boolean) params.getDynValue("precalculateEnvelope"))  ) {
204
                FeatureType featureType = this.getStoreServices().getDefaultFeatureType();
205
                if( !StringUtils.isEmpty(featureType.getDefaultGeometryAttributeName()) ) {
206
                    Thread thread = new Thread(new Runnable() {
207
                        @Override
208
                        public void run() {
209 44058 jjdelcerro
                            LOGGER.debug("Precalculating envelope of '"+getSourceId()+"'.");
210 43361 jjdelcerro
                            getEnvelopeValue().get();
211
                        }
212
                    }, "PrecalculateEnvelopeOfDBTable");
213
                    thread.start();
214
                    Thread.sleep(1);
215
                }
216
           }
217
        } catch(Exception ex) {
218 44058 jjdelcerro
            LOGGER.warn("Probems precalculating the envelope of table '"+this.getSourceId()+"'.", ex);
219 43361 jjdelcerro
        }
220 43020 jjdelcerro
    }
221
222
    @Override
223
    public JDBCStoreParameters getParameters() {
224
        return (JDBCStoreParameters) super.getParameters();
225
    }
226
227
    @Override
228
    public JDBCHelper getHelper() {
229
        return helper;
230
    }
231
232
    public OperationsFactory getOperations() {
233
        return this.getHelper().getOperations();
234
    }
235
236
    @Override
237
    public String getProviderName() {
238
        return this.getHelper().getProviderName();
239
    }
240
241
    @Override
242
    public int getOIDType() {
243
        return DataTypes.UNKNOWN;
244
    }
245
246
    @Override
247
    public Object createNewOID() {
248
        return null;
249
    }
250
251
    @Override
252
    public boolean allowAutomaticValues() {
253
        return this.getHelper().allowAutomaticValues();
254
    }
255
256
    @Override
257
    public boolean allowWrite() {
258
        return this.getAllowWriteValue().get();
259
    }
260
261
    @Override
262
    public Object getDynValue(String name) throws DynFieldNotFoundException {
263
        try {
264
            if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
265
                Envelope env = this.getEnvelope();
266
                if (env != null) {
267
                    return env;
268
                }
269
            } else if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
270
                IProjection proj;
271
                proj = this.getFeatureStore().getDefaultFeatureType().getDefaultSRS();
272
                if (proj != null) {
273
                    return proj;
274
                }
275
            }
276
        } catch (DataException e) {
277
            throw new RuntimeException(e);
278
        }
279
        return super.getDynValue(name);
280
    }
281
282
    @Override
283
    public CalculatedValue<Long> getCountValue() {
284
        if( this.count == null ) {
285
            this.count = new CountValue();
286
        }
287
        return this.count;
288
    }
289
290
    @Override
291
    public CalculatedValue<Envelope> getEnvelopeValue() {
292
        if( this.envelope == null ) {
293
            this.envelope = new EnvelopeValue();
294
        }
295
        return this.envelope;
296
    }
297
298
    @Override
299
    public CalculatedValue<Boolean> getAllowWriteValue() {
300
        if( this.allowWrite == null ) {
301
            this.allowWrite = new AllowWriteValue();
302
        }
303
        return this.allowWrite;
304
    }
305
306
    @Override
307
    public long getFeatureCount() throws DataException {
308
        return this.getCountValue().get();
309
    }
310
311
    @Override
312
    public boolean closeResourceRequested(ResourceProvider resource) {
313
        ResulSetControler resulSetControler = this.getHelper().getResulSetControler();
314
        resulSetControler.pack();
315
        return resulSetControler.getOpenCount() == 0;
316
    }
317
318
    @Override
319
    public void close() throws CloseException {
320
        JDBCUtils.closeQuietly(this.getHelper());
321
    }
322
323
    @Override
324
    public void resourceChanged(ResourceProvider resource) {
325
        this.getStoreServices().notifyChange(
326
                DataStoreNotification.RESOURCE_CHANGED,
327
                resource
328
        );
329
    }
330
331
    @Override
332
    public DataServerExplorer getExplorer() throws ReadException {
333
        DataManager manager = DALLocator.getDataManager();
334
        JDBCServerExplorerParameters exParams;
335
        JDBCStoreParameters params = getParameters();
336
        try {
337
            exParams = this.getHelper().createServerExplorerParameters();
338 44185 jjdelcerro
            DynField[] fields = exParams.getDynClass().getDynFields();
339
            for (DynField field : fields) {
340
                try {
341
                    exParams.setDynValue(field.getName(), params.getDynValue(field.getName()));
342
                } catch(Exception ex) {
343
                    // Ignore
344
                }
345
            }
346 43020 jjdelcerro
            exParams.setHost(params.getHost());
347
            exParams.setPort(params.getPort());
348
            exParams.setDBName(params.getDBName());
349
            exParams.setUser(params.getUser());
350
            exParams.setPassword(params.getPassword());
351
            exParams.setUrl(params.getUrl());
352
            exParams.setCatalog(params.getCatalog());
353
            exParams.setSchema(params.getSchema());
354
            exParams.setJDBCDriverClassName(params.getJDBCDriverClassName());
355
356
            return manager.openServerExplorer(exParams.getExplorerName(), exParams);
357
        } catch (Exception e) {
358
            throw new ReadException(this.getProviderName(), e);
359
        }
360
    }
361
362
    @Override
363
    protected void doDispose() throws BaseException {
364
        this.close();
365
        this.getHelper().dispose();
366
        super.doDispose();
367
    }
368
369
    @Override
370
    public String getSourceId() {
371 43361 jjdelcerro
        try {
372
            return this.getHelper().getSourceId(this.getParameters());
373
        } catch(Exception ex) {
374
            return "unknow";
375
        }
376 43020 jjdelcerro
    }
377
378
    @Override
379
    public String getName() {
380 43397 jjdelcerro
        return this.getParameters().getTable();
381 43020 jjdelcerro
    }
382
383
    @Override
384
    public String getFullName() {
385
        return this.getHelper().getSourceId(this.getParameters());
386
    }
387
388 43409 jjdelcerro
    private static class DummyResource extends AbstractResource {
389
390
        private final String name;
391
392
        DummyResource(String name) throws InitializeException {
393
            super((ResourceParameters)null);
394
            this.name = name;
395
        }
396
397
        @Override
398
        public String getName() throws AccessResourceException {
399
            return MessageFormat.format("DummyResource({0})",
400
                                new Object[] { this.name });
401
        }
402
403
        @Override
404
        public Object get() throws AccessResourceException {
405
            return null;
406
        }
407
408
        @Override
409
        public boolean isThis(ResourceParameters parameters) throws ResourceException {
410
            return true;
411
        }
412
413
    }
414
415 43020 jjdelcerro
    @Override
416
    public ResourceProvider getResource() {
417 43409 jjdelcerro
        ResourceProvider r = getHelper().getResource();
418
        if( r == null ) {
419
            try {
420
                r = new DummyResource(this.getName());
421
            } catch (InitializeException ex) {
422 44058 jjdelcerro
                LOGGER.warn("Can't create DummyResource",ex);
423 43409 jjdelcerro
                // Do nothing
424
            }
425
        }
426
        return r;
427 43020 jjdelcerro
    }
428
429
    @Override
430
    public void open() throws OpenException {
431
432
    }
433
434
    @Override
435
    public FeatureSetProvider createSet(
436
            FeatureQuery query,
437
            FeatureType featureType
438
        ) throws DataException {
439
440
        FeatureSetProvider set = new JDBCSetProvider(
441
                this,
442
                this.getHelper(),
443
                query,
444
                featureType
445
        );
446
447
        return set;
448
    }
449
450
    protected void initializeFeatureType() {
451
        EditableFeatureType type = this.getStoreServices().createFeatureType(getName());
452
        JDBCStoreParameters params = this.getParameters();
453
        List<String> primaryKeys = null;
454
        if( params.getPkFields() != null ) {
455
            primaryKeys = Arrays.asList(params.getPkFields());
456
        }
457
        FetchFeatureTypeOperation fetchFeatureType =
458
             this.getOperations().createFetchFeatureType(
459
                type,
460 44058 jjdelcerro
                this.getOperations().createTableReference(params),
461 43020 jjdelcerro
                primaryKeys,
462
                params.getDefaultGeometryField(),
463
                params.getCRS()
464
            );
465
        fetchFeatureType.perform();
466
467 43420 jjdelcerro
        if( !StringUtils.isEmpty(params.getDefaultGeometryField()) ) {
468
            if( !params.getDefaultGeometryField().equalsIgnoreCase(type.getDefaultGeometryAttributeName()) ) {
469
                type.setDefaultGeometryAttributeName(params.getDefaultGeometryField());
470
                EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) type.getDefaultGeometryAttribute();
471
                attr.setGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
472
            }
473
        }
474 43020 jjdelcerro
        FeatureType defaultType = type.getNotEditableCopy();
475
        List<FeatureType> types = Collections.singletonList(defaultType);
476
        this.getStoreServices().setFeatureTypes(types, defaultType);
477
    }
478
479
    @Override
480
    protected FeatureProvider internalGetFeatureProviderByReference(
481
            FeatureReferenceProviderServices reference,
482
            FeatureType featureType
483
        ) throws DataException {
484
        JDBCStoreParameters params = this.getParameters();
485
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference =
486
            this.getOperations().createFetchFeatureProviderByReference(
487
                reference,
488
                featureType,
489 44058 jjdelcerro
                this.getOperations().createTableReference(params)
490 43020 jjdelcerro
            );
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 44058 jjdelcerro
                this.getOperations().createTableReference(params),
509 43020 jjdelcerro
                type,
510
                deleteds,
511
                inserteds,
512
                updateds,
513
                featureTypesChanged
514
        );
515
        performChanges.perform();
516
        if( performChanges.isTypeChanged() ) {
517
            // Get rules before initializing feature type
518
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
519
520
             // This initialization loses the feature type rules
521
            this.initializeFeatureType();
522
523
            // Get new feature type, clear rules and add the ones saved previously
524
            FeatureType featureType = getFeatureStore().getDefaultFeatureType();
525
            FeatureRules rules = featureType.getRules();
526
            rules.clear();
527
            for (FeatureRule rule : saved_rules) {
528
                rules.add(rule);
529
            }
530
        }
531
        this.getCountValue().reset();
532
        this.getEnvelopeValue().reset();
533
    }
534
535
    @Override
536
    public boolean supportsAppendMode() {
537
        return true;
538
    }
539
540
    protected AppendOperation getAppendOperation() throws DataException {
541
        if( this.appendOperation == null ) {
542
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
543
            JDBCStoreParameters params = this.getParameters();
544
            this.appendOperation = this.getOperations().createAppend(
545 44058 jjdelcerro
                this.getOperations().createTableReference(params),
546 43020 jjdelcerro
                type
547
            );
548
        }
549
        return this.appendOperation;
550
    }
551
552
    @Override
553
    public void endAppend() throws DataException {
554
        this.getAppendOperation().end();
555
    }
556
557
    @Override
558 43408 jjdelcerro
    public void abortAppend() throws DataException {
559
        this.getAppendOperation().abort();
560
    }
561
562
    @Override
563 43020 jjdelcerro
    public void beginAppend() throws DataException {
564
        this.getAppendOperation().begin();
565
    }
566
567
    @Override
568
    public void append(final FeatureProvider featureProvider) throws DataException {
569
        this.getAppendOperation().append(featureProvider);
570
    }
571
572
    @Override
573
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
574
            throws DataException {
575
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
576
    }
577
}