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

History | View | Annotate | Download (19.9 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 44376 jjdelcerro
            try {
77
                JDBCStoreParameters params = getParameters();
78
                CountOperation count = getOperations().createCount(
79
                        getFeatureStore().getDefaultFeatureType(),
80
                        getOperations().createTableReference(params),
81
                        params.getBaseFilter(),
82
                        null
83
                );
84
                this.value = (Long) count.perform();
85
            } catch (DataException ex) {
86
                throw new RuntimeException("Can't calculate count",ex);
87
            }
88 43020 jjdelcerro
        }
89
90
        @Override
91
        public void reset() {
92
            this.value = null;
93
        }
94
95
        @Override
96
        public Long get() {
97
            if( this.value == null ) {
98
                this.calculate();
99
            }
100
            return this.value;
101
        }
102
    }
103
104
    public class EnvelopeValue implements CalculatedValue<Envelope> {
105
106
        private Envelope value = null;
107 43163 jjdelcerro
        private boolean needCalculate = true;
108 43020 jjdelcerro
109
        @Override
110
        public void calculate() {
111
            try {
112 43163 jjdelcerro
                value = null;
113 43020 jjdelcerro
                String columnName = getFeatureStore()
114
                        .getDefaultFeatureType()
115
                        .getDefaultGeometryAttributeName();
116 43163 jjdelcerro
                if( columnName==null ) {
117
                    return;
118
                }
119 43020 jjdelcerro
                IProjection crs = getFeatureStore()
120
                        .getDefaultFeatureType()
121
                        .getDefaultSRS();
122
                JDBCStoreParameters params = getParameters();
123
                CalculateEnvelopeOfColumnOperation calculateEnvelopeOfColumn =
124
                    getOperations().createCalculateEnvelopeOfColumn(
125 44376 jjdelcerro
                        getFeatureStore().getDefaultFeatureType(),
126 44058 jjdelcerro
                        getOperations().createTableReference(params),
127 43020 jjdelcerro
                        columnName,
128
                        params.getBaseFilter(),
129
                        params.getWorkingArea(),
130
                        crs
131
                    );
132
                value = (Envelope) calculateEnvelopeOfColumn.perform();
133 43163 jjdelcerro
134 43020 jjdelcerro
            } catch(Exception ex) {
135
                throw new RuntimeException("Can't calculate envelope.", ex);
136 43163 jjdelcerro
            } finally {
137
               needCalculate = false;
138 43020 jjdelcerro
            }
139
        }
140
141
        @Override
142
        public void reset() {
143
            this.value = null;
144 43163 jjdelcerro
            this.needCalculate = true;
145 43020 jjdelcerro
        }
146
147
        @Override
148 43361 jjdelcerro
        public synchronized Envelope get() {
149 43163 jjdelcerro
            if( needCalculate ) {
150 43020 jjdelcerro
                this.calculate();
151
            }
152
            return this.value;
153
        }
154
    }
155 43163 jjdelcerro
156 43020 jjdelcerro
    public class AllowWriteValue implements CalculatedValue<Boolean> {
157
158
        private Boolean value = null;
159
160
        @Override
161
        public void calculate() {
162
            try {
163
                JDBCStoreParameters params = getParameters();
164
                CanModifyTableOperation canModifyTable =
165
                    getOperations().createCanModifyTableOperation(
166 44058 jjdelcerro
                        getOperations().createTableReference(params)
167 43020 jjdelcerro
                    );
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 44058 jjdelcerro
    @SuppressWarnings({"OverridableMethodCallInConstructor", "CallToThreadStartDuringObjectConstruction"})
199 43020 jjdelcerro
    protected JDBCStoreProviderBase(
200
            JDBCStoreParameters params,
201
            DataStoreProviderServices storeServices,
202
            DynObject metadata,
203
            JDBCHelper helper
204
    ) throws InitializeException {
205
        super(params, storeServices, metadata);
206
        this.helper = helper;
207
        this.initializeFeatureType();
208 43361 jjdelcerro
        try {
209
            if( BooleanUtils.isTrue((Boolean) params.getDynValue("precalculateEnvelope"))  ) {
210
                FeatureType featureType = this.getStoreServices().getDefaultFeatureType();
211
                if( !StringUtils.isEmpty(featureType.getDefaultGeometryAttributeName()) ) {
212
                    Thread thread = new Thread(new Runnable() {
213
                        @Override
214
                        public void run() {
215 44750 jjdelcerro
                            LOGGER.trace("Precalculating envelope of '"+getSourceId()+"'.");
216 43361 jjdelcerro
                            getEnvelopeValue().get();
217
                        }
218
                    }, "PrecalculateEnvelopeOfDBTable");
219
                    thread.start();
220
                    Thread.sleep(1);
221
                }
222
           }
223
        } catch(Exception ex) {
224 44058 jjdelcerro
            LOGGER.warn("Probems precalculating the envelope of table '"+this.getSourceId()+"'.", ex);
225 43361 jjdelcerro
        }
226 43020 jjdelcerro
    }
227
228
    @Override
229
    public JDBCStoreParameters getParameters() {
230
        return (JDBCStoreParameters) super.getParameters();
231
    }
232
233
    @Override
234
    public JDBCHelper getHelper() {
235
        return helper;
236
    }
237
238
    public OperationsFactory getOperations() {
239
        return this.getHelper().getOperations();
240
    }
241
242
    @Override
243
    public String getProviderName() {
244
        return this.getHelper().getProviderName();
245
    }
246
247
    @Override
248
    public int getOIDType() {
249
        return DataTypes.UNKNOWN;
250
    }
251
252
    @Override
253
    public Object createNewOID() {
254
        return null;
255
    }
256
257
    @Override
258
    public boolean allowAutomaticValues() {
259
        return this.getHelper().allowAutomaticValues();
260
    }
261
262
    @Override
263
    public boolean allowWrite() {
264
        return this.getAllowWriteValue().get();
265
    }
266
267
    @Override
268
    public Object getDynValue(String name) throws DynFieldNotFoundException {
269
        try {
270
            if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
271
                Envelope env = this.getEnvelope();
272
                if (env != null) {
273
                    return env;
274
                }
275
            } else if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
276
                IProjection proj;
277
                proj = this.getFeatureStore().getDefaultFeatureType().getDefaultSRS();
278
                if (proj != null) {
279
                    return proj;
280
                }
281
            }
282
        } catch (DataException e) {
283
            throw new RuntimeException(e);
284
        }
285
        return super.getDynValue(name);
286
    }
287
288
    @Override
289
    public CalculatedValue<Long> getCountValue() {
290
        if( this.count == null ) {
291
            this.count = new CountValue();
292
        }
293
        return this.count;
294
    }
295
296
    @Override
297
    public CalculatedValue<Envelope> getEnvelopeValue() {
298
        if( this.envelope == null ) {
299
            this.envelope = new EnvelopeValue();
300
        }
301
        return this.envelope;
302
    }
303
304
    @Override
305
    public CalculatedValue<Boolean> getAllowWriteValue() {
306
        if( this.allowWrite == null ) {
307
            this.allowWrite = new AllowWriteValue();
308
        }
309
        return this.allowWrite;
310
    }
311
312
    @Override
313
    public long getFeatureCount() throws DataException {
314
        return this.getCountValue().get();
315
    }
316
317
    @Override
318
    public boolean closeResourceRequested(ResourceProvider resource) {
319
        ResulSetControler resulSetControler = this.getHelper().getResulSetControler();
320
        resulSetControler.pack();
321
        return resulSetControler.getOpenCount() == 0;
322
    }
323
324
    @Override
325
    public void close() throws CloseException {
326
        JDBCUtils.closeQuietly(this.getHelper());
327
    }
328
329
    @Override
330
    public void resourceChanged(ResourceProvider resource) {
331
        this.getStoreServices().notifyChange(
332
                DataStoreNotification.RESOURCE_CHANGED,
333
                resource
334
        );
335
    }
336
337
    @Override
338
    public DataServerExplorer getExplorer() throws ReadException {
339
        DataManager manager = DALLocator.getDataManager();
340
        JDBCServerExplorerParameters exParams;
341
        JDBCStoreParameters params = getParameters();
342
        try {
343
            exParams = this.getHelper().createServerExplorerParameters();
344 44185 jjdelcerro
            DynField[] fields = exParams.getDynClass().getDynFields();
345
            for (DynField field : fields) {
346
                try {
347
                    exParams.setDynValue(field.getName(), params.getDynValue(field.getName()));
348
                } catch(Exception ex) {
349
                    // Ignore
350
                }
351
            }
352 43020 jjdelcerro
            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 43361 jjdelcerro
        try {
378
            return this.getHelper().getSourceId(this.getParameters());
379
        } catch(Exception ex) {
380
            return "unknow";
381
        }
382 43020 jjdelcerro
    }
383
384
    @Override
385
    public String getName() {
386 43397 jjdelcerro
        return this.getParameters().getTable();
387 43020 jjdelcerro
    }
388
389
    @Override
390
    public String getFullName() {
391
        return this.getHelper().getSourceId(this.getParameters());
392
    }
393
394 43409 jjdelcerro
    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 43020 jjdelcerro
    @Override
422
    public ResourceProvider getResource() {
423 43409 jjdelcerro
        ResourceProvider r = getHelper().getResource();
424
        if( r == null ) {
425
            try {
426
                r = new DummyResource(this.getName());
427
            } catch (InitializeException ex) {
428 44058 jjdelcerro
                LOGGER.warn("Can't create DummyResource",ex);
429 43409 jjdelcerro
                // Do nothing
430
            }
431
        }
432
        return r;
433 43020 jjdelcerro
    }
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 44058 jjdelcerro
                this.getOperations().createTableReference(params),
467 43020 jjdelcerro
                primaryKeys,
468
                params.getDefaultGeometryField(),
469
                params.getCRS()
470
            );
471
        fetchFeatureType.perform();
472
473 44331 jjdelcerro
        if( !StringUtils.isBlank(params.getDefaultGeometryField()) ) {
474 43420 jjdelcerro
            if( !params.getDefaultGeometryField().equalsIgnoreCase(type.getDefaultGeometryAttributeName()) ) {
475
                type.setDefaultGeometryAttributeName(params.getDefaultGeometryField());
476
                EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) type.getDefaultGeometryAttribute();
477
                attr.setGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
478
            }
479
        }
480 43020 jjdelcerro
        FeatureType defaultType = type.getNotEditableCopy();
481
        List<FeatureType> types = Collections.singletonList(defaultType);
482
        this.getStoreServices().setFeatureTypes(types, defaultType);
483
    }
484
485
    @Override
486
    protected FeatureProvider internalGetFeatureProviderByReference(
487
            FeatureReferenceProviderServices reference,
488
            FeatureType featureType
489
        ) throws DataException {
490
        JDBCStoreParameters params = this.getParameters();
491
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference =
492
            this.getOperations().createFetchFeatureProviderByReference(
493
                reference,
494
                featureType,
495 44058 jjdelcerro
                this.getOperations().createTableReference(params)
496 43020 jjdelcerro
            );
497
        FeatureProvider feature = (FeatureProvider) fetchFeatureProviderByReference.perform();
498
        return feature;
499
    }
500
501
    @Override
502
    public Envelope getEnvelope() throws DataException {
503
        return this.getEnvelopeValue().get();
504
    }
505
506
    @Override
507
    public void performChanges(Iterator deleteds, Iterator inserteds,
508
                    Iterator updateds, Iterator featureTypesChanged)
509
                    throws DataException {
510
511
        FeatureType type = this.getFeatureStore().getDefaultFeatureType();
512
        JDBCStoreParameters params = this.getParameters();
513
        PerformChangesOperation performChanges = this.getOperations().createPerformChanges(
514 44058 jjdelcerro
                this.getOperations().createTableReference(params),
515 43020 jjdelcerro
                type,
516
                deleteds,
517
                inserteds,
518
                updateds,
519
                featureTypesChanged
520
        );
521
        performChanges.perform();
522
        if( performChanges.isTypeChanged() ) {
523
            // Get rules before initializing feature type
524
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
525
526
             // This initialization loses the feature type rules
527
            this.initializeFeatureType();
528
529
            // Get new feature type, clear rules and add the ones saved previously
530
            FeatureType featureType = getFeatureStore().getDefaultFeatureType();
531
            FeatureRules rules = featureType.getRules();
532
            rules.clear();
533
            for (FeatureRule rule : saved_rules) {
534
                rules.add(rule);
535
            }
536
        }
537
        this.getCountValue().reset();
538
        this.getEnvelopeValue().reset();
539
    }
540
541
    @Override
542
    public boolean supportsAppendMode() {
543
        return true;
544
    }
545
546
    protected AppendOperation getAppendOperation() throws DataException {
547
        if( this.appendOperation == null ) {
548
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
549
            JDBCStoreParameters params = this.getParameters();
550
            this.appendOperation = this.getOperations().createAppend(
551 44058 jjdelcerro
                this.getOperations().createTableReference(params),
552 43020 jjdelcerro
                type
553
            );
554
        }
555
        return this.appendOperation;
556
    }
557
558
    @Override
559
    public void endAppend() throws DataException {
560
        this.getAppendOperation().end();
561
    }
562
563
    @Override
564 43408 jjdelcerro
    public void abortAppend() throws DataException {
565
        this.getAppendOperation().abort();
566
    }
567
568
    @Override
569 43020 jjdelcerro
    public void beginAppend() throws DataException {
570
        this.getAppendOperation().begin();
571
    }
572
573
    @Override
574
    public void append(final FeatureProvider featureProvider) throws DataException {
575
        this.getAppendOperation().append(featureProvider);
576
    }
577
578
    @Override
579
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
580
            throws DataException {
581
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
582
    }
583
}