Statistics
| Revision:

svn-gvsig-desktop / trunk / org.gvsig.desktop / org.gvsig.desktop.compat.cdc / org.gvsig.fmap.dal / org.gvsig.fmap.dal.impl / src / main / java / org / gvsig / fmap / dal / feature / impl / DefaultForeingKey.java @ 46737

History | View | Annotate | Download (21.4 KB)

1
package org.gvsig.fmap.dal.feature.impl;
2

    
3
import org.gvsig.fmap.dal.feature.EditableForeingKey;
4
import org.gvsig.fmap.dal.feature.ForeingKey;
5
import java.util.List;
6
import java.util.Objects;
7
import org.apache.commons.lang3.StringUtils;
8
import org.gvsig.expressionevaluator.Expression;
9
import org.gvsig.expressionevaluator.ExpressionBuilder;
10
import org.gvsig.expressionevaluator.ExpressionUtils;
11
import org.gvsig.expressionevaluator.MutableSymbolTable;
12
import org.gvsig.expressionevaluator.SymbolTable;
13
import org.gvsig.fmap.dal.DALLocator;
14
import org.gvsig.fmap.dal.DataManager;
15
import org.gvsig.fmap.dal.DataStore;
16
import org.gvsig.fmap.dal.StoresRepository;
17
import org.gvsig.fmap.dal.exception.DataException;
18
import org.gvsig.fmap.dal.expressionevaluator.FeatureSymbolTable;
19
import org.gvsig.fmap.dal.feature.Feature;
20
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
21
import org.gvsig.fmap.dal.feature.FeatureQuery;
22
import org.gvsig.fmap.dal.feature.FeatureSet;
23
import org.gvsig.fmap.dal.feature.FeatureStore;
24
import org.gvsig.fmap.dal.feature.FeatureType;
25
import static org.gvsig.fmap.dal.feature.ForeingKey.MAX_AVAILABLE_VALUES;
26
import org.gvsig.tools.ToolsLocator;
27
import org.gvsig.tools.dispose.DisposeUtils;
28
import org.gvsig.tools.dynobject.DynObject;
29
import org.gvsig.tools.dynobject.DynObjectValueItem;
30
import org.gvsig.tools.dynobject.DynStruct;
31
import org.gvsig.tools.persistence.PersistenceManager;
32
import org.gvsig.tools.persistence.Persistent;
33
import org.gvsig.tools.persistence.PersistentState;
34
import org.gvsig.tools.persistence.exception.PersistenceException;
35
import org.slf4j.Logger;
36
import org.slf4j.LoggerFactory;
37

    
38
/**
39
 *
40
 * @author jjdelcerro
41
 */
42
@SuppressWarnings("UseSpecificCatch")
43
public class DefaultForeingKey implements Persistent, ForeingKey, EditableForeingKey, org.gvsig.tools.lang.Cloneable {
44

    
45
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultForeingKey.class);
46

    
47
    private class DefaultContextForeingKey implements ContextForeingKey {
48

    
49
        private FeatureStore featureStore = null;
50
        private StoresRepository storesRepository = null;
51
        private Expression labelExpression;
52
        private SymbolTable symbolTable;
53
        private FeatureSymbolTable featureSymbolTable;
54
        private DynObject contextValues;
55
        private int refs;
56

    
57
        public DefaultContextForeingKey(StoresRepository storesRepository) {
58
            this.refs = 1;
59
            this.storesRepository = storesRepository;
60
        }
61

    
62
        public void addRef() {
63
            this.refs++;
64
        }
65

    
66
        public void relese() {
67
            this.refs--;
68
        }
69

    
70
        @Override
71
        public void dispose() {
72
            DisposeUtils.disposeQuietly(featureStore);
73
            DisposeUtils.disposeQuietly(contextValues);
74
            this.featureStore = null;
75
            this.storesRepository = null;
76
            this.labelExpression = null;
77
            this.symbolTable = null;
78
            this.featureSymbolTable = null;
79
        }
80

    
81
        @Override
82
        public StoresRepository getStoresRepository() {
83
            if (this.storesRepository == null) {
84
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
85
            }
86
            return this.storesRepository;
87
        }
88

    
89
        @Override
90
        public FeatureStore getFeatureStore() {
91
            if (this.featureStore == null) {
92
                StoresRepository repository = this.getStoresRepository();
93
                this.featureStore = (FeatureStore) repository.getStore(tableName);
94
                if (this.featureStore == null) {
95
                    LOGGER.warn("Can't locate store '" + tableName + "' to get available values.");
96
                    return null;
97
                }
98
            }
99
            return this.featureStore;
100
        }
101

    
102
        @Override
103
        public Expression getLabelExpression() {
104
            if (this.labelExpression == null) {
105
                if (StringUtils.isBlank(labelFormula)) {
106
                    return null;
107
                }
108
                this.labelExpression = ExpressionUtils.createExpression(labelFormula);
109
            }
110
            return this.labelExpression;
111
        }
112

    
113
        @Override
114
        public FeatureSymbolTable getFeatureSymbolTable() {
115
            if (this.featureSymbolTable == null) {
116
                DataManager dataManager = DALLocator.getDataManager();
117
                this.featureSymbolTable = dataManager.createFeatureSymbolTable();
118
                this.symbolTable = this.featureSymbolTable.createParent();
119
            }
120
            return this.featureSymbolTable;
121
        }
122

    
123
        @Override
124
        public SymbolTable getSymbolTable() {
125
            if (this.symbolTable == null) {
126
                DataManager dataManager = DALLocator.getDataManager();
127
                this.featureSymbolTable = dataManager.createFeatureSymbolTable();
128
                this.symbolTable = this.featureSymbolTable.createParent();
129
            }
130
            return this.symbolTable;
131
        }
132

    
133
        @Override
134
        public DynObject getContextValues() {
135
            return this.contextValues;
136
    }
137

    
138
        @Override
139
        public void setContextValues(DynObject values) {
140
            this.contextValues = values;
141
        }
142
    }
143

    
144
    private boolean foreingKey;
145
    private boolean closedList;
146
    private String labelFormula;
147
    private String tableName;
148
    private String codeName;
149
    private DynObjectValueItem[] availableValues;
150
    private boolean loadAvailableValues;
151
    private String repositoryIDOfAvailableValues;
152
    private String repositoryLabelOfAvailableValues;
153
    private boolean ensureReferentialIntegrity;
154
    private StoresRepository storesRepository = null;
155
    private FeatureAttributeDescriptor descriptor;
156

    
157
    public DefaultForeingKey() {
158
        this.foreingKey = false;
159
        this.closedList = false;
160
        this.tableName = null;
161
        this.codeName = null;
162
        this.labelFormula = null;
163
        this.ensureReferentialIntegrity = false;
164
        this.loadAvailableValues = true;
165
        this.repositoryIDOfAvailableValues = null;
166
        this.repositoryLabelOfAvailableValues = null;
167
    }
168

    
169
    public void setDescriptor(FeatureAttributeDescriptor descriptor) {
170
        this.descriptor = descriptor;
171
    }
172
    
173
    private StoresRepository getStoresRepository() {
174
        if( this.descriptor == null ) {
175
            this.storesRepository = DALLocator.getDataManager().getStoresRepository();
176
        } else {
177
            FeatureStore store = descriptor.getStore();
178
            if( store==null ) {
179
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
180
            } else {
181
                this.storesRepository = store.getStoresRepository();
182
            }
183
        }
184
        return this.storesRepository;
185
    }
186
    
187
    @Override
188
    public void unbind() {
189
        this.getStoresRepository(); // Force get stores repository
190
        this.descriptor = null;
191
    }
192

    
193
    @Override
194
    public boolean isClosedList() {
195
        return this.closedList;
196
    }
197

    
198
    @Override
199
    public void setClosedList(boolean selectable) {
200
        this.closedList = selectable;
201
        // Force reload available values 
202
        this.availableValues = null;
203
        this.loadAvailableValues = true;
204
    }
205

    
206
    @Override
207
    public boolean isForeingKey() {
208
        return this.foreingKey;
209
    }
210

    
211
    @Override
212
    public void setForeingKey(boolean foreingKey) {
213
        this.foreingKey = foreingKey;
214
        // Force reload available values 
215
        this.availableValues = null;
216
        this.loadAvailableValues = true;
217
    }
218

    
219
    @Override
220
    public String getLabelFormula() {
221
        return this.labelFormula;
222
    }
223

    
224
    @Override
225
    public void setLabelFormula(String labelFormula) {
226
        this.labelFormula = labelFormula;
227
        // Force reload available values with new formula
228
        this.availableValues = null;
229
        this.loadAvailableValues = true;
230
    }
231

    
232
    @Override
233
    public String getCodeName() {
234
        return this.codeName;
235
    }
236

    
237
    @Override
238
    public void setCodeName(String codeName) {
239
        this.codeName = codeName;
240
    }
241

    
242
    @Override
243
    public String getTableName() {
244
        return this.tableName;
245
    }
246

    
247
    @Override
248
    public void setTableName(String tableName) {
249
        this.tableName = tableName;
250
        // Force reload available values 
251
        this.availableValues = null;
252
        this.loadAvailableValues = true;
253
    }
254

    
255
    @Override
256
    public boolean isEmpty() {
257
        if (!this.foreingKey
258
                && !this.closedList
259
                && StringUtils.isBlank(this.tableName)
260
                && StringUtils.isBlank(this.codeName)
261
                && StringUtils.isBlank(this.labelFormula)) {
262
            return true;
263
        }
264
        return false;
265
    }
266

    
267
    @Override
268
    public void clean() {
269
        this.foreingKey = false;
270
        this.closedList = false;
271
        this.tableName = null;
272
        this.codeName = null;
273
        this.labelFormula = null;
274
        this.ensureReferentialIntegrity = false;
275
    }
276

    
277
    private void disposeIfLocalContext(ContextForeingKey context) {
278
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
279
        c.relese();
280
        if (c.refs == 0) {
281
            context.dispose();
282
        }
283
    }
284

    
285
    private ContextForeingKey createLocalContextIfNull(ContextForeingKey context) {
286
        if (context == null) {
287
            return createContext();
288
        }
289
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
290
        c.addRef();
291
        return c;
292
    }
293

    
294
    @Override
295
    public ContextForeingKey createContext() {
296
        return new DefaultContextForeingKey(this.getStoresRepository());
297
    }
298

    
299
    @Override
300
    public StoresRepository getStoresRepository(ContextForeingKey context) {
301
        context = createLocalContextIfNull(context);
302
        try {
303
            return context.getStoresRepository();
304
        } finally {
305
            disposeIfLocalContext(context);
306
        }
307
    }
308

    
309
    @Override
310
    public FeatureStore getFeatureStore(ContextForeingKey context) {
311
        context = createLocalContextIfNull(context);
312
        try {
313
            return context.getFeatureStore();
314
        } finally {
315
            disposeIfLocalContext(context);
316
        }
317
    }
318

    
319
    @Override
320
    public FeatureType getFeatureType(ContextForeingKey context) {
321
        context = createLocalContextIfNull(context);
322
        FeatureStore store = context.getFeatureStore();
323
        if (store == null) {
324
            return null;
325
        }
326
        try {
327
            return store.getDefaultFeatureType();
328
        } catch (DataException ex) {
329
            return null;
330
        } finally {
331
            disposeIfLocalContext(context);
332
        }
333
    }
334

    
335
    @Override
336
    public List<Feature> getFeatures(ContextForeingKey context) {
337
        context = createLocalContextIfNull(context);
338
        FeatureStore store = context.getFeatureStore();
339
        if (store == null) {
340
            return null;
341
        }
342
        try {
343
            return store.getFeatures();
344
        } finally {
345
            disposeIfLocalContext(context);
346
        }
347
    }
348

    
349
    @Override
350
    public Object getCode(ContextForeingKey context, Feature feature) {
351
//        context = createLocalContextIfNull(context);
352
        try {
353
            return feature.get(codeName);
354
        } finally {
355
//            disposeIfLocalContext(context);
356
        }
357
    }
358

    
359
    @Override
360
    public FeatureQuery getQuery(ContextForeingKey context, Object codeValue) {
361
        context = createLocalContextIfNull(context);
362
        try {
363
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
364
            FeatureStore store = context.getFeatureStore();
365
            FeatureQuery query = store.createFeatureQuery();
366
            query.setFilter(builder.eq(
367
                    builder.variable(codeName),
368
                    builder.constant(codeValue)
369
            ).toString()
370
            );
371
            query.retrievesAllAttributes();
372
            return query;
373
        } finally {
374
            disposeIfLocalContext(context);
375
        }
376
    }
377

    
378
    @Override
379
    public Feature getFeature(ContextForeingKey context, Object codeValue) {
380
        context = createLocalContextIfNull(context);
381
        try {
382
            FeatureStore store = context.getFeatureStore();
383
            if (store == null) {
384
                return null;
385
            }
386
            FeatureQuery query = this.getQuery(context, codeValue);
387
            Feature feature = store.findFirst(query);
388
            return feature;
389
        } catch (DataException ex) {
390
            return null;
391
        } finally {
392
            disposeIfLocalContext(context);
393
        }
394
    }
395

    
396
    @Override
397
    public String getLabel(ContextForeingKey context, Object codeValue) {
398
        context = createLocalContextIfNull(context);
399
        try {
400
            Feature feature = this.getFeature(context, codeValue);
401
            if (feature == null) {
402
                return null;
403
            }
404
            return getLabel(context, feature);
405
        } finally {
406
            disposeIfLocalContext(context);
407
        }
408
    }
409

    
410
    @Override
411
    public Expression getLabelExpression(ContextForeingKey context) {
412
        context = createLocalContextIfNull(context);
413
        try {
414
            return context.getLabelExpression();
415
        } finally {
416
            disposeIfLocalContext(context);
417
        }
418
    }
419

    
420
    @Override
421
    public String getLabel(ContextForeingKey context, Feature feature) {
422
        if (feature == null) {
423
            return null;
424
        }
425
        context = createLocalContextIfNull(context);
426
        try {
427
            Expression labelExpression = context.getLabelExpression();
428
            if (labelExpression == null) {
429
                return feature.toString();
430
            }
431
            context.getFeatureSymbolTable().setFeature(feature);
432
            Object x = labelExpression.execute(context.getSymbolTable());
433
            if (x == null) {
434
                return null;
435
            }
436
            return x.toString();
437
        } finally {
438
            disposeIfLocalContext(context);
439
        }
440
    }
441
    
442
    @Override
443
    public DynObjectValueItem[] getAvailableValues(ContextForeingKey context) {
444
        if (!this.isClosedList()) {
445
            return null;
446
        }
447
        StoresRepository theStoresRepository = this.getStoresRepository(context);
448
        if( theStoresRepository==null ) {
449
            LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.descriptor.getName()+ "' from table '" + this.getTableName() + "', can't locate the stores-repository.");
450
            return null;
451
        }
452
        theStoresRepository = theStoresRepository.getRepositoryOfStore(this.getTableName());
453
        if( theStoresRepository==null ) {
454
            LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.descriptor.getName()+ "' from table '" + this.getTableName() + "', can't locate the stores-repository from the table.");
455
            return null;
456
        }
457
        
458
        if ((this.availableValues == null && this.loadAvailableValues) || 
459
                !StringUtils.equalsIgnoreCase(theStoresRepository.getID(), this.repositoryIDOfAvailableValues) ||
460
                !StringUtils.equalsIgnoreCase(theStoresRepository.getLabel(), this.repositoryLabelOfAvailableValues)
461
                ) {
462

    
463
            LOGGER.info("Loading available values for field '" + this.getStoreName() + "." + this.descriptor.getName()+ "' from table '" + this.getTableName() + "'.");
464
            FeatureStore foreingStore = null;
465
            FeatureSet.DisposableFeatureSetIterable set = null;
466

    
467
            try {
468

    
469
                this.repositoryLabelOfAvailableValues = theStoresRepository.getLabel();
470
                this.repositoryIDOfAvailableValues = theStoresRepository.getID();
471
                foreingStore = (FeatureStore) theStoresRepository.getStore(
472
                        this.getTableName()
473
                );
474
                Expression labelExpression = this.getLabelExpression(null);
475
                String theCodeName =  this.getCodeName();
476
                FeatureSymbolTable featureSymbolTable = DALLocator.getDataManager().createFeatureSymbolTable();
477
                MutableSymbolTable symbolTable = featureSymbolTable.createParent();
478

    
479
                int count = (int) foreingStore.getFeatureCount();
480
                if( count < 1) {
481
                    LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.descriptor.getName()+ "' from table '" + this.getTableName() + "'("+DataStore.getFullNameQuietly(foreingStore)+").");
482
                }
483
                DynObjectValueItem[] values = new DynObjectValueItem[Math.min(count, MAX_AVAILABLE_VALUES)];
484
                int n = 0;
485
                for (Feature feature : set = foreingStore.getFeatureSet().iterable()) {
486
                    Object code = feature.get(theCodeName);
487
                    Object value;
488
                    if (labelExpression == null) {
489
                        value = code;
490
                    } else {
491
                        featureSymbolTable.setFeature(feature);
492
                        try {
493
                            value = labelExpression.execute(symbolTable);
494
                        } catch (Exception ex) {
495
                            LOGGER.warn("Can't get label from table: "+this.tableName+" with expression: "+labelExpression.getPhrase(), ex);
496
                            values = null;
497
                            break;
498
                        }
499
                    }
500
                    values[n++] = new DynObjectValueItem(code, Objects.toString(value, Objects.toString(code, "##ERROR##")));
501
                    if (n >= MAX_AVAILABLE_VALUES) {
502
                        break;
503
                    }
504
                }
505
                this.availableValues = values;
506

    
507
            } catch (Exception ex) {
508
                LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.descriptor.getName() + "' from table '" + this.getTableName() + "' ("+DataStore.getFullNameQuietly(foreingStore)+").", ex);
509
            } finally {
510
                this.loadAvailableValues = false;
511
                DisposeUtils.disposeQuietly(set);
512
                DisposeUtils.disposeQuietly(foreingStore);                
513
            }
514
        }
515
        return this.availableValues;
516
    }
517
    
518
    private String getStoreName() {
519
        if (this.descriptor==null) {
520
            return "Unknown";
521
        }
522
        return this.descriptor.getStore().getName();
523
    }
524

    
525
    @Override
526
    public String getLabelForValue(Object value) {
527
        DynObjectValueItem[] values = this.getAvailableValues(null);
528
        if (values != null) {
529
            for (DynObjectValueItem value1 : values) {
530
                if (Objects.equals(value, value1.getValue())) {
531
                    return value1.getLabel();
532
                }
533
            }
534
        }
535
        return Objects.toString(value, "##ERROR##");
536
    }
537

    
538
    @Override
539
    public void loadFromState(PersistentState state)
540
            throws PersistenceException {
541
        foreingKey = state.getBoolean("foreingKey");
542
        closedList = state.getBoolean("selectable");
543
        labelFormula = state.getString("labelFormula");
544
        codeName = state.getString("codeName");
545
        tableName = state.getString("tableName");
546
        ensureReferentialIntegrity = state.getBoolean("ensureReferentialIntegrity");
547
    }
548

    
549
    @Override
550
    public void saveToState(PersistentState state) throws PersistenceException {
551
        state.set("foreingKey", foreingKey);
552
        state.set("selectable", closedList);
553
        state.set("labelFormula", labelFormula);
554
        state.set("codeName", codeName);
555
        state.set("tableName", tableName);
556
        state.set("ensureReferentialIntegrity", ensureReferentialIntegrity);
557
    }
558

    
559
    private static final String FOREINGKEY_PERSISTENCE_DEFINITION_NAME = "ForeingKey";
560

    
561
    public static void registerPersistenceDefinition() {
562
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
563

    
564
        if (manager.getDefinition(FOREINGKEY_PERSISTENCE_DEFINITION_NAME)
565
                == null) {
566
            DynStruct definition = manager.addDefinition(DefaultForeingKey.class,
567
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME,
568
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME
569
                    + " persistent definition",
570
                    null,
571
                    null
572
            );
573
            definition.addDynFieldBoolean("foreingKey");
574
            definition.addDynFieldBoolean("selectable");
575
            definition.addDynFieldString("LabelFormula");
576
            definition.addDynFieldString("codeName");
577
            definition.addDynFieldString("tableName");
578
            definition.addDynFieldBoolean("ensureReferentialIntegrity");
579
        }
580
    }
581

    
582
    @Override
583
    public ForeingKey clone() throws CloneNotSupportedException {
584
        DefaultForeingKey other = (DefaultForeingKey) super.clone();
585
        return other;
586
    }
587

    
588
    @Override
589
    public boolean getEnsureReferentialIntegrity() {
590
        return this.ensureReferentialIntegrity;
591
    }
592

    
593
    @Override
594
    public void setEnsureReferentialIntegrity(boolean ensureReferentialIntegrity) {
595
        this.ensureReferentialIntegrity = ensureReferentialIntegrity;
596
    }
597

    
598
    @Override
599
    public boolean isInAvailableValues(Object valueToCheck) {
600
        if (this.hasAvailableValues() && availableValues.length > 0) {
601
            for (DynObjectValueItem availableValue : availableValues) {
602
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
603
                    return true;
604
                }
605
            }
606
        }
607
        return false;
608
    }
609

    
610
    @Override
611
    public boolean hasAvailableValues() {
612
        if (this.availableValues == null) {
613
            this.getAvailableValues(null);
614
        }
615
        return this.availableValues != null;
616
    }
617

    
618
}