Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.db / org.gvsig.fmap.dal.db.jdbc / src / main / java / org / gvsig / fmap / dal / store / jdbc2 / spi / JDBCStoreProviderBase.java @ 43420

History | View | Annotate | Download (19.8 KB)

1 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 43409 jjdelcerro
import java.util.logging.Level;
10 43361 jjdelcerro
import org.apache.commons.lang3.BooleanUtils;
11
import org.apache.commons.lang3.StringUtils;
12 43020 jjdelcerro
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 43420 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
25 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.EditableFeatureType;
26 43420 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
27 43020 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureQuery;
28
import org.gvsig.fmap.dal.feature.FeatureRule;
29
import org.gvsig.fmap.dal.feature.FeatureRules;
30
import org.gvsig.fmap.dal.feature.FeatureType;
31
import org.gvsig.fmap.dal.feature.spi.AbstractFeatureStoreProvider;
32
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
33
import org.gvsig.fmap.dal.feature.spi.FeatureReferenceProviderServices;
34
import org.gvsig.fmap.dal.feature.spi.FeatureSetProvider;
35 43409 jjdelcerro
import org.gvsig.fmap.dal.resource.ResourceParameters;
36
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
37
import org.gvsig.fmap.dal.resource.exception.ResourceException;
38
import org.gvsig.fmap.dal.resource.spi.AbstractResource;
39 43020 jjdelcerro
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
40
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
41
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
42
//import org.gvsig.fmap.dal.store.jdbc2.JDBCServerExplorerBase;
43
import org.gvsig.fmap.dal.store.jdbc.JDBCServerExplorerParameters;
44
import org.gvsig.fmap.dal.store.jdbc.JDBCStoreParameters;
45
import org.gvsig.fmap.dal.store.jdbc2.JDBCHelper;
46
import org.gvsig.fmap.dal.store.jdbc2.JDBCUtils;
47
import org.gvsig.fmap.dal.store.jdbc2.OperationsFactory;
48
import org.gvsig.fmap.dal.store.jdbc2.ResulSetControler;
49
import org.gvsig.fmap.dal.store.jdbc2.impl.JDBCSetProvider;
50
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.AppendOperation;
51
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CalculateEnvelopeOfColumnOperation;
52
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CanModifyTableOperation;
53
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.CountOperation;
54
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureProviderByReferenceOperation;
55
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.FetchFeatureTypeOperation;
56
import org.gvsig.fmap.dal.store.jdbc2.spi.operations.PerformChangesOperation;
57 43420 jjdelcerro
import org.gvsig.fmap.geom.Geometry;
58 43020 jjdelcerro
import org.gvsig.fmap.geom.primitive.Envelope;
59
import org.gvsig.tools.dynobject.DynObject;
60
import org.gvsig.tools.dynobject.exception.DynFieldNotFoundException;
61
import org.gvsig.tools.exception.BaseException;
62
import org.slf4j.Logger;
63
import org.slf4j.LoggerFactory;
64
65
public class JDBCStoreProviderBase
66
        extends AbstractFeatureStoreProvider
67
        implements ResourceConsumer, JDBCStoreProvider {
68
69
    final static private Logger logger = LoggerFactory.getLogger(JDBCStoreProviderBase.class);
70
71
    public class CountValue implements CalculatedValue<Long> {
72
73
        private Long value = null;
74
75
        @Override
76
        public void calculate() {
77
            JDBCStoreParameters params = getParameters();
78
            CountOperation count = getOperations().createCount(
79
                    params.getDBName(),
80
                    params.getSchema(),
81
                    params.getTable(),
82
                    params.getSQL(),
83
                    params.getBaseFilter(),
84
                    null
85
            );
86
            this.value = (Long) count.perform();
87
        }
88
89
        @Override
90
        public void reset() {
91
            this.value = null;
92
        }
93
94
        @Override
95
        public Long get() {
96
            if( this.value == null ) {
97
                this.calculate();
98
            }
99
            return this.value;
100
        }
101
    }
102
103
    public class EnvelopeValue implements CalculatedValue<Envelope> {
104
105
        private Envelope value = null;
106 43163 jjdelcerro
        private boolean needCalculate = true;
107 43020 jjdelcerro
108
        @Override
109
        public void calculate() {
110
            try {
111 43163 jjdelcerro
                value = null;
112 43020 jjdelcerro
                String columnName = getFeatureStore()
113
                        .getDefaultFeatureType()
114
                        .getDefaultGeometryAttributeName();
115 43163 jjdelcerro
                if( columnName==null ) {
116
                    return;
117
                }
118 43020 jjdelcerro
                IProjection crs = getFeatureStore()
119
                        .getDefaultFeatureType()
120
                        .getDefaultSRS();
121
                JDBCStoreParameters params = getParameters();
122
                CalculateEnvelopeOfColumnOperation calculateEnvelopeOfColumn =
123
                    getOperations().createCalculateEnvelopeOfColumn(
124
                        params.getSQL(),
125
                        params.getDBName(),
126
                        params.getSchema(),
127
                        params.getTable(),
128
                        columnName,
129
                        params.getBaseFilter(),
130
                        params.getWorkingArea(),
131
                        crs
132
                    );
133
                value = (Envelope) calculateEnvelopeOfColumn.perform();
134 43163 jjdelcerro
135 43020 jjdelcerro
            } catch(Exception ex) {
136
                throw new RuntimeException("Can't calculate envelope.", ex);
137 43163 jjdelcerro
            } finally {
138
               needCalculate = false;
139 43020 jjdelcerro
            }
140
        }
141
142
        @Override
143
        public void reset() {
144
            this.value = null;
145 43163 jjdelcerro
            this.needCalculate = true;
146 43020 jjdelcerro
        }
147
148
        @Override
149 43361 jjdelcerro
        public synchronized Envelope get() {
150 43163 jjdelcerro
            if( needCalculate ) {
151 43020 jjdelcerro
                this.calculate();
152
            }
153
            return this.value;
154
        }
155
    }
156 43163 jjdelcerro
157 43020 jjdelcerro
    public class AllowWriteValue implements CalculatedValue<Boolean> {
158
159
        private Boolean value = null;
160
161
        @Override
162
        public void calculate() {
163
            try {
164
                JDBCStoreParameters params = getParameters();
165
                CanModifyTableOperation canModifyTable =
166
                    getOperations().createCanModifyTableOperation(
167
                        params.getDBName(),
168
                        params.getSchema(),
169
                        params.getTable()
170
                    );
171
                this.value = (boolean) canModifyTable.perform();
172
            } catch(Exception ex) {
173
                throw new RuntimeException("Can't determine if allow write.", ex);
174
            }
175
        }
176
177
        @Override
178
        public void reset() {
179
            this.value = null;
180
        }
181
182
        @Override
183
        public Boolean get() {
184
            if( this.value == null ) {
185
                this.calculate();
186
            }
187
            return this.value;
188
        }
189
    }
190
191
    protected final JDBCHelper helper;
192
193
    protected CalculatedValue<Long> count = null;
194
195
    protected CalculatedValue<Envelope> envelope = null;
196
197
    protected CalculatedValue<Boolean> allowWrite = null;
198
199
    protected AppendOperation appendOperation = null;
200
201
    protected JDBCStoreProviderBase(
202
            JDBCStoreParameters params,
203
            DataStoreProviderServices storeServices,
204
            DynObject metadata,
205
            JDBCHelper helper
206
    ) throws InitializeException {
207
        super(params, storeServices, metadata);
208
        this.helper = helper;
209
        this.initializeFeatureType();
210 43361 jjdelcerro
        try {
211
            if( BooleanUtils.isTrue((Boolean) params.getDynValue("precalculateEnvelope"))  ) {
212
                FeatureType featureType = this.getStoreServices().getDefaultFeatureType();
213
                if( !StringUtils.isEmpty(featureType.getDefaultGeometryAttributeName()) ) {
214
                    Thread thread = new Thread(new Runnable() {
215
                        @Override
216
                        public void run() {
217
                            logger.debug("Precalculating envelope of '"+getSourceId()+"'.");
218
                            getEnvelopeValue().get();
219
                        }
220
                    }, "PrecalculateEnvelopeOfDBTable");
221
                    thread.start();
222
                    Thread.sleep(1);
223
                }
224
           }
225
        } catch(Exception ex) {
226
            logger.warn("Probems precalculating the envelope of table '"+this.getSourceId()+"'.", ex);
227
        }
228 43020 jjdelcerro
    }
229
230
231
    @Override
232 43088 jjdelcerro
    public JDBCSQLBuilderBase createExpression() {
233 43020 jjdelcerro
        return this.getHelper().createSQLBuilder();
234
    }
235
236
    @Override
237
    public JDBCStoreParameters getParameters() {
238
        return (JDBCStoreParameters) super.getParameters();
239
    }
240
241
    @Override
242
    public JDBCHelper getHelper() {
243
        return helper;
244
    }
245
246
    public OperationsFactory getOperations() {
247
        return this.getHelper().getOperations();
248
    }
249
250
    @Override
251
    public String getProviderName() {
252
        return this.getHelper().getProviderName();
253
    }
254
255
    @Override
256
    public int getOIDType() {
257
        return DataTypes.UNKNOWN;
258
    }
259
260
    @Override
261
    public Object createNewOID() {
262
        return null;
263
    }
264
265
    @Override
266
    public boolean allowAutomaticValues() {
267
        return this.getHelper().allowAutomaticValues();
268
    }
269
270
    @Override
271
    public boolean allowWrite() {
272
        return this.getAllowWriteValue().get();
273
    }
274
275
    @Override
276
    public Object getDynValue(String name) throws DynFieldNotFoundException {
277
        try {
278
            if (DataStore.METADATA_ENVELOPE.equalsIgnoreCase(name)) {
279
                Envelope env = this.getEnvelope();
280
                if (env != null) {
281
                    return env;
282
                }
283
            } else if (DataStore.METADATA_CRS.equalsIgnoreCase(name)) {
284
                IProjection proj;
285
                proj = this.getFeatureStore().getDefaultFeatureType().getDefaultSRS();
286
                if (proj != null) {
287
                    return proj;
288
                }
289
            }
290
        } catch (DataException e) {
291
            throw new RuntimeException(e);
292
        }
293
        return super.getDynValue(name);
294
    }
295
296
    @Override
297
    public CalculatedValue<Long> getCountValue() {
298
        if( this.count == null ) {
299
            this.count = new CountValue();
300
        }
301
        return this.count;
302
    }
303
304
    @Override
305
    public CalculatedValue<Envelope> getEnvelopeValue() {
306
        if( this.envelope == null ) {
307
            this.envelope = new EnvelopeValue();
308
        }
309
        return this.envelope;
310
    }
311
312
    @Override
313
    public CalculatedValue<Boolean> getAllowWriteValue() {
314
        if( this.allowWrite == null ) {
315
            this.allowWrite = new AllowWriteValue();
316
        }
317
        return this.allowWrite;
318
    }
319
320
    @Override
321
    public long getFeatureCount() throws DataException {
322
        return this.getCountValue().get();
323
    }
324
325
    @Override
326
    public boolean closeResourceRequested(ResourceProvider resource) {
327
        ResulSetControler resulSetControler = this.getHelper().getResulSetControler();
328
        resulSetControler.pack();
329
        return resulSetControler.getOpenCount() == 0;
330
    }
331
332
    @Override
333
    public void close() throws CloseException {
334
        JDBCUtils.closeQuietly(this.getHelper());
335
    }
336
337
    @Override
338
    public void resourceChanged(ResourceProvider resource) {
339
        this.getStoreServices().notifyChange(
340
                DataStoreNotification.RESOURCE_CHANGED,
341
                resource
342
        );
343
    }
344
345
    @Override
346
    public DataServerExplorer getExplorer() throws ReadException {
347
        DataManager manager = DALLocator.getDataManager();
348
        JDBCServerExplorerParameters exParams;
349
        JDBCStoreParameters params = getParameters();
350
        try {
351
            exParams = this.getHelper().createServerExplorerParameters();
352
            exParams.setHost(params.getHost());
353
            exParams.setPort(params.getPort());
354
            exParams.setDBName(params.getDBName());
355
            exParams.setUser(params.getUser());
356
            exParams.setPassword(params.getPassword());
357
            exParams.setUrl(params.getUrl());
358
            exParams.setCatalog(params.getCatalog());
359
            exParams.setSchema(params.getSchema());
360
            exParams.setJDBCDriverClassName(params.getJDBCDriverClassName());
361
362
            return manager.openServerExplorer(exParams.getExplorerName(), exParams);
363
        } catch (Exception e) {
364
            throw new ReadException(this.getProviderName(), e);
365
        }
366
    }
367
368
    @Override
369
    protected void doDispose() throws BaseException {
370
        this.close();
371
        this.getHelper().dispose();
372
        super.doDispose();
373
    }
374
375
    @Override
376
    public String getSourceId() {
377 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
                logger.warn("Can't create DummyResource",ex);
429
                // 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
                params.getDBName(),
467
                params.getSchema(),
468
                params.getTable(),
469
                primaryKeys,
470
                params.getDefaultGeometryField(),
471
                params.getCRS()
472
            );
473
        fetchFeatureType.perform();
474
475 43420 jjdelcerro
        if( !StringUtils.isEmpty(params.getDefaultGeometryField()) ) {
476
            if( !params.getDefaultGeometryField().equalsIgnoreCase(type.getDefaultGeometryAttributeName()) ) {
477
                type.setDefaultGeometryAttributeName(params.getDefaultGeometryField());
478
                EditableFeatureAttributeDescriptor attr = (EditableFeatureAttributeDescriptor) type.getDefaultGeometryAttribute();
479
                attr.setGeometryType(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D);
480
            }
481
        }
482 43020 jjdelcerro
        FeatureType defaultType = type.getNotEditableCopy();
483
        List<FeatureType> types = Collections.singletonList(defaultType);
484
        this.getStoreServices().setFeatureTypes(types, defaultType);
485
    }
486
487
    @Override
488
    protected FeatureProvider internalGetFeatureProviderByReference(
489
            FeatureReferenceProviderServices reference,
490
            FeatureType featureType
491
        ) throws DataException {
492
        JDBCStoreParameters params = this.getParameters();
493
        FetchFeatureProviderByReferenceOperation fetchFeatureProviderByReference =
494
            this.getOperations().createFetchFeatureProviderByReference(
495
                reference,
496
                featureType,
497
                params.getDBName(),
498
                params.getSchema(),
499
                params.getTable()
500
            );
501
        FeatureProvider feature = (FeatureProvider) fetchFeatureProviderByReference.perform();
502
        return feature;
503
    }
504
505
    @Override
506
    public Envelope getEnvelope() throws DataException {
507
        return this.getEnvelopeValue().get();
508
    }
509
510
    @Override
511
    public void performChanges(Iterator deleteds, Iterator inserteds,
512
                    Iterator updateds, Iterator featureTypesChanged)
513
                    throws DataException {
514
515
        FeatureType type = this.getFeatureStore().getDefaultFeatureType();
516
        JDBCStoreParameters params = this.getParameters();
517
        PerformChangesOperation performChanges = this.getOperations().createPerformChanges(
518
                params.getDBName(),
519
                params.getSchema(),
520
                params.getTable(),
521
                type,
522
                deleteds,
523
                inserteds,
524
                updateds,
525
                featureTypesChanged
526
        );
527
        performChanges.perform();
528
        if( performChanges.isTypeChanged() ) {
529
            // Get rules before initializing feature type
530
            FeatureRules saved_rules = getFeatureStore().getDefaultFeatureType().getRules();
531
532
             // This initialization loses the feature type rules
533
            this.initializeFeatureType();
534
535
            // Get new feature type, clear rules and add the ones saved previously
536
            FeatureType featureType = getFeatureStore().getDefaultFeatureType();
537
            FeatureRules rules = featureType.getRules();
538
            rules.clear();
539
            for (FeatureRule rule : saved_rules) {
540
                rules.add(rule);
541
            }
542
        }
543
        this.getCountValue().reset();
544
        this.getEnvelopeValue().reset();
545
    }
546
547
    @Override
548
    public boolean supportsAppendMode() {
549
        return true;
550
    }
551
552
    protected AppendOperation getAppendOperation() throws DataException {
553
        if( this.appendOperation == null ) {
554
            FeatureType type = this.getFeatureStore().getDefaultFeatureType();
555
            JDBCStoreParameters params = this.getParameters();
556
            this.appendOperation = this.getOperations().createAppend(
557
                params.getDBName(),
558
                params.getSchema(),
559
                params.getTable(),
560
                type
561
            );
562
        }
563
        return this.appendOperation;
564
    }
565
566
    @Override
567
    public void endAppend() throws DataException {
568
        this.getAppendOperation().end();
569
    }
570
571
    @Override
572 43408 jjdelcerro
    public void abortAppend() throws DataException {
573
        this.getAppendOperation().abort();
574
    }
575
576
    @Override
577 43020 jjdelcerro
    public void beginAppend() throws DataException {
578
        this.getAppendOperation().begin();
579
    }
580
581
    @Override
582
    public void append(final FeatureProvider featureProvider) throws DataException {
583
        this.getAppendOperation().append(featureProvider);
584
    }
585
586
    @Override
587
    public boolean canWriteGeometry(int geometryType, int geometrySubtype)
588
            throws DataException {
589
        return this.getHelper().canWriteGeometry(geometryType,geometrySubtype);
590
    }
591
}