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

History | View | Annotate | Download (19.3 KB)

1 44262 jjdelcerro
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 45772 omartinez
import org.gvsig.expressionevaluator.MutableSymbolTable;
12 44262 jjdelcerro
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.StoresRepository;
16
import org.gvsig.fmap.dal.exception.DataException;
17
import org.gvsig.fmap.dal.expressionevaluator.FeatureSymbolTable;
18
import org.gvsig.fmap.dal.feature.Feature;
19
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
20
import org.gvsig.fmap.dal.feature.FeatureQuery;
21 45772 omartinez
import org.gvsig.fmap.dal.feature.FeatureSet;
22 44262 jjdelcerro
import org.gvsig.fmap.dal.feature.FeatureStore;
23
import org.gvsig.fmap.dal.feature.FeatureType;
24 45772 omartinez
import static org.gvsig.fmap.dal.feature.ForeingKey.MAX_AVAILABLE_VALUES;
25 44262 jjdelcerro
import org.gvsig.tools.ToolsLocator;
26
import org.gvsig.tools.dispose.DisposeUtils;
27 45739 jjdelcerro
import org.gvsig.tools.dynobject.DynObject;
28 44262 jjdelcerro
import org.gvsig.tools.dynobject.DynObjectValueItem;
29
import org.gvsig.tools.dynobject.DynStruct;
30
import org.gvsig.tools.persistence.PersistenceManager;
31
import org.gvsig.tools.persistence.Persistent;
32
import org.gvsig.tools.persistence.PersistentState;
33
import org.gvsig.tools.persistence.exception.PersistenceException;
34
import org.slf4j.Logger;
35
import org.slf4j.LoggerFactory;
36
37
/**
38
 *
39
 * @author jjdelcerro
40
 */
41
@SuppressWarnings("UseSpecificCatch")
42
public class DefaultForeingKey implements Persistent, ForeingKey, EditableForeingKey, org.gvsig.tools.lang.Cloneable {
43
44
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultForeingKey.class);
45
46
    private class DefaultContextForeingKey implements ContextForeingKey {
47
48
        private FeatureStore featureStore = null;
49
        private StoresRepository storesRepository = null;
50
        private Expression labelExpression;
51
        private SymbolTable symbolTable;
52
        private FeatureSymbolTable featureSymbolTable;
53 45739 jjdelcerro
        private DynObject contextValues;
54 44262 jjdelcerro
        private int refs;
55
56 45772 omartinez
        public DefaultContextForeingKey(StoresRepository storesRepository) {
57 44262 jjdelcerro
            this.refs = 1;
58 45772 omartinez
            this.storesRepository = storesRepository;
59 44262 jjdelcerro
        }
60 45772 omartinez
61 44262 jjdelcerro
        public void addRef() {
62
            this.refs++;
63
        }
64
65
        public void relese() {
66
            this.refs--;
67
        }
68 45772 omartinez
69 44262 jjdelcerro
        @Override
70
        public void dispose() {
71
            DisposeUtils.disposeQuietly(featureStore);
72 45739 jjdelcerro
            DisposeUtils.disposeQuietly(contextValues);
73 44262 jjdelcerro
            this.featureStore = null;
74
            this.storesRepository = null;
75
            this.labelExpression = null;
76
            this.symbolTable = null;
77
            this.featureSymbolTable = null;
78
        }
79
80
        @Override
81
        public StoresRepository getStoresRepository() {
82
            if (this.storesRepository == null) {
83 45772 omartinez
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
84 44262 jjdelcerro
            }
85
            return this.storesRepository;
86
        }
87
88
        @Override
89
        public FeatureStore getFeatureStore() {
90
            if (this.featureStore == null) {
91
                StoresRepository repository = this.getStoresRepository();
92 44304 jjdelcerro
                this.featureStore = (FeatureStore) repository.getStore(tableName);
93 44262 jjdelcerro
                if (this.featureStore == null) {
94 45772 omartinez
                    LOGGER.warn("Can't locate store '" + tableName + "' to get available values.");
95 44262 jjdelcerro
                    return null;
96
                }
97
            }
98
            return this.featureStore;
99
        }
100
101
        @Override
102
        public Expression getLabelExpression() {
103
            if (this.labelExpression == null) {
104
                if (StringUtils.isBlank(labelFormula)) {
105
                    return null;
106
                }
107
                this.labelExpression = ExpressionUtils.createExpression(labelFormula);
108
            }
109
            return this.labelExpression;
110
        }
111
112
        @Override
113
        public FeatureSymbolTable getFeatureSymbolTable() {
114
            if (this.featureSymbolTable == null) {
115
                DataManager dataManager = DALLocator.getDataManager();
116
                this.featureSymbolTable = dataManager.createFeatureSymbolTable();
117
                this.symbolTable = this.featureSymbolTable.createParent();
118
            }
119
            return this.featureSymbolTable;
120
        }
121
122
        @Override
123
        public SymbolTable getSymbolTable() {
124
            if (this.symbolTable == null) {
125
                DataManager dataManager = DALLocator.getDataManager();
126
                this.featureSymbolTable = dataManager.createFeatureSymbolTable();
127
                this.symbolTable = this.featureSymbolTable.createParent();
128
            }
129
            return this.symbolTable;
130
        }
131 45739 jjdelcerro
132
        @Override
133
        public DynObject getContextValues() {
134
            return this.contextValues;
135 45772 omartinez
    }
136 45739 jjdelcerro
137
        @Override
138
        public void setContextValues(DynObject values) {
139
            this.contextValues = values;
140
        }
141 44262 jjdelcerro
    }
142
143
    private boolean foreingKey;
144 44338 jjdelcerro
    private boolean closedList;
145 44262 jjdelcerro
    private String labelFormula;
146
    private String tableName;
147
    private String codeName;
148 44338 jjdelcerro
    private DynObjectValueItem[] availableValues;
149 45946 omartinez
    private boolean loadAvailableValues;
150 44363 jjdelcerro
    private boolean ensureReferentialIntegrity;
151 45772 omartinez
    private StoresRepository storesRepository = null;
152 44262 jjdelcerro
    private FeatureAttributeDescriptor descriptor;
153
154
    public DefaultForeingKey() {
155 44363 jjdelcerro
        this.foreingKey = false;
156
        this.closedList = false;
157
        this.tableName = null;
158
        this.codeName = null;
159
        this.labelFormula = null;
160
        this.ensureReferentialIntegrity = false;
161 45946 omartinez
        this.loadAvailableValues = true;
162 44262 jjdelcerro
    }
163
164
    public void setDescriptor(FeatureAttributeDescriptor descriptor) {
165
        this.descriptor = descriptor;
166 45775 jjdelcerro
    }
167
168
    private StoresRepository getStoresRepository() {
169
        if( this.descriptor == null ) {
170 45772 omartinez
            this.storesRepository = DALLocator.getDataManager().getStoresRepository();
171
        } else {
172 45775 jjdelcerro
            FeatureStore store = descriptor.getStore();
173
            if( store==null ) {
174
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
175
            } else {
176
                this.storesRepository = store.getStoresRepository();
177
            }
178 45772 omartinez
        }
179 45775 jjdelcerro
        return this.storesRepository;
180 44262 jjdelcerro
    }
181 45772 omartinez
182 45775 jjdelcerro
    @Override
183 45772 omartinez
    public void unbind() {
184 45775 jjdelcerro
        this.getStoresRepository(); // Force get stores repository
185 45772 omartinez
        this.descriptor = null;
186
    }
187 44262 jjdelcerro
188
    @Override
189 44338 jjdelcerro
    public boolean isClosedList() {
190
        return this.closedList;
191 44262 jjdelcerro
    }
192
193
    @Override
194 44338 jjdelcerro
    public void setClosedList(boolean selectable) {
195
        this.closedList = selectable;
196 44262 jjdelcerro
    }
197
198
    @Override
199
    public boolean isForeingKey() {
200
        return this.foreingKey;
201
    }
202
203
    @Override
204
    public void setForeingKey(boolean foreingKey) {
205
        this.foreingKey = foreingKey;
206
    }
207
208
    @Override
209
    public String getLabelFormula() {
210
        return this.labelFormula;
211
    }
212
213
    @Override
214
    public void setLabelFormula(String labelFormula) {
215
        this.labelFormula = labelFormula;
216 45946 omartinez
        // Force reload available values with new formula
217
        this.availableValues = null;
218
        this.loadAvailableValues = true;
219 44262 jjdelcerro
    }
220
221
    @Override
222
    public String getCodeName() {
223
        return this.codeName;
224
    }
225
226
    @Override
227
    public void setCodeName(String codeName) {
228
        this.codeName = codeName;
229
    }
230
231
    @Override
232
    public String getTableName() {
233
        return this.tableName;
234
    }
235
236
    @Override
237
    public void setTableName(String tableName) {
238
        this.tableName = tableName;
239
    }
240
241
    @Override
242
    public boolean isEmpty() {
243
        if (!this.foreingKey
244 44338 jjdelcerro
                && !this.closedList
245 44262 jjdelcerro
                && StringUtils.isBlank(this.tableName)
246
                && StringUtils.isBlank(this.codeName)
247
                && StringUtils.isBlank(this.labelFormula)) {
248
            return true;
249
        }
250
        return false;
251
    }
252
253
    @Override
254
    public void clean() {
255
        this.foreingKey = false;
256 44338 jjdelcerro
        this.closedList = false;
257 44262 jjdelcerro
        this.tableName = null;
258
        this.codeName = null;
259
        this.labelFormula = null;
260 44363 jjdelcerro
        this.ensureReferentialIntegrity = false;
261 44262 jjdelcerro
    }
262
263
    private void disposeIfLocalContext(ContextForeingKey context) {
264
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
265
        c.relese();
266 45772 omartinez
        if (c.refs == 0) {
267 44262 jjdelcerro
            context.dispose();
268
        }
269
    }
270
271
    private ContextForeingKey createLocalContextIfNull(ContextForeingKey context) {
272
        if (context == null) {
273 45772 omartinez
            return createContext();
274 44262 jjdelcerro
        }
275
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
276
        c.addRef();
277
        return c;
278
    }
279
280
    @Override
281
    public ContextForeingKey createContext() {
282 45775 jjdelcerro
        return new DefaultContextForeingKey(this.getStoresRepository());
283 44262 jjdelcerro
    }
284
285
    @Override
286
    public StoresRepository getStoresRepository(ContextForeingKey context) {
287
        context = createLocalContextIfNull(context);
288
        try {
289
            return context.getStoresRepository();
290
        } finally {
291
            disposeIfLocalContext(context);
292
        }
293
    }
294
295
    @Override
296
    public FeatureStore getFeatureStore(ContextForeingKey context) {
297
        context = createLocalContextIfNull(context);
298
        try {
299
            return context.getFeatureStore();
300
        } finally {
301
            disposeIfLocalContext(context);
302
        }
303
    }
304
305
    @Override
306
    public FeatureType getFeatureType(ContextForeingKey context) {
307
        context = createLocalContextIfNull(context);
308
        FeatureStore store = context.getFeatureStore();
309
        if (store == null) {
310
            return null;
311
        }
312
        try {
313
            return store.getDefaultFeatureType();
314
        } catch (DataException ex) {
315
            return null;
316
        } finally {
317
            disposeIfLocalContext(context);
318
        }
319
    }
320
321
    @Override
322
    public List<Feature> getFeatures(ContextForeingKey context) {
323
        context = createLocalContextIfNull(context);
324
        FeatureStore store = context.getFeatureStore();
325
        if (store == null) {
326
            return null;
327
        }
328
        try {
329
            return store.getFeatures();
330
        } finally {
331
            disposeIfLocalContext(context);
332
        }
333
    }
334
335
    @Override
336
    public Object getCode(ContextForeingKey context, Feature feature) {
337
//        context = createLocalContextIfNull(context);
338
        try {
339
            return feature.get(codeName);
340
        } finally {
341
//            disposeIfLocalContext(context);
342
        }
343
    }
344
345
    @Override
346
    public FeatureQuery getQuery(ContextForeingKey context, Object codeValue) {
347
        context = createLocalContextIfNull(context);
348
        try {
349
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
350
            FeatureStore store = context.getFeatureStore();
351
            FeatureQuery query = store.createFeatureQuery();
352
            query.setFilter(builder.eq(
353
                    builder.variable(codeName),
354
                    builder.constant(codeValue)
355
            ).toString()
356
            );
357
            query.retrievesAllAttributes();
358
            return query;
359
        } finally {
360
            disposeIfLocalContext(context);
361
        }
362
    }
363
364
    @Override
365
    public Feature getFeature(ContextForeingKey context, Object codeValue) {
366
        context = createLocalContextIfNull(context);
367
        try {
368
            FeatureStore store = context.getFeatureStore();
369
            if (store == null) {
370
                return null;
371
            }
372
            FeatureQuery query = this.getQuery(context, codeValue);
373
            Feature feature = store.findFirst(query);
374
            return feature;
375
        } catch (DataException ex) {
376
            return null;
377
        } finally {
378
            disposeIfLocalContext(context);
379
        }
380
    }
381
382
    @Override
383
    public String getLabel(ContextForeingKey context, Object codeValue) {
384
        context = createLocalContextIfNull(context);
385
        try {
386
            Feature feature = this.getFeature(context, codeValue);
387
            if (feature == null) {
388
                return null;
389
            }
390
            return getLabel(context, feature);
391
        } finally {
392
            disposeIfLocalContext(context);
393
        }
394
    }
395
396
    @Override
397
    public Expression getLabelExpression(ContextForeingKey context) {
398
        context = createLocalContextIfNull(context);
399
        try {
400
            return context.getLabelExpression();
401
        } finally {
402
            disposeIfLocalContext(context);
403
        }
404
    }
405
406
    @Override
407
    public String getLabel(ContextForeingKey context, Feature feature) {
408
        if (feature == null) {
409
            return null;
410
        }
411
        context = createLocalContextIfNull(context);
412
        try {
413
            Expression labelExpression = context.getLabelExpression();
414
            if (labelExpression == null) {
415
                return feature.toString();
416
            }
417
            context.getFeatureSymbolTable().setFeature(feature);
418
            Object x = labelExpression.execute(context.getSymbolTable());
419
            if (x == null) {
420
                return null;
421
            }
422
            return x.toString();
423
        } finally {
424
            disposeIfLocalContext(context);
425
        }
426
    }
427
428
    @Override
429
    public DynObjectValueItem[] getAvailableValues(ContextForeingKey context) {
430 44338 jjdelcerro
        if (!this.isClosedList()) {
431 44262 jjdelcerro
            return null;
432
        }
433 45946 omartinez
        if (this.availableValues == null && this.loadAvailableValues) {
434 45772 omartinez
435
            FeatureStore foreingStore = null;
436
            FeatureSet.DisposableFeatureSetIterable set = null;
437
438
            try {
439
440
                StoresRepository theStoresRepository = this.getStoresRepository(context);
441
442
                foreingStore = (FeatureStore) theStoresRepository.getStore(
443
                        this.getTableName()
444
                );
445
                Expression labelExpression = this.getLabelExpression(null);
446
                String theCodeName =  this.getCodeName();
447
                FeatureSymbolTable featureSymbolTable = DALLocator.getDataManager().createFeatureSymbolTable();
448
                MutableSymbolTable symbolTable = featureSymbolTable.createParent();
449
450
                int count = (int) foreingStore.getFeatureCount();
451
                DynObjectValueItem[] values = new DynObjectValueItem[Math.min(count, MAX_AVAILABLE_VALUES)];
452
                int n = 0;
453
                for (Feature feature : set = foreingStore.getFeatureSet().iterable()) {
454
                    Object code = feature.get(theCodeName);
455
                    Object value;
456
                    if (labelExpression == null) {
457
                        value = code;
458
                    } else {
459
                        featureSymbolTable.setFeature(feature);
460 45946 omartinez
                        try {
461
                            value = labelExpression.execute(symbolTable);
462
                        } catch (Exception ex) {
463
                            LOGGER.warn("Can't get label from table: "+this.tableName+" with expression: "+labelExpression.getPhrase(), ex);
464
                            values = null;
465
                            break;
466
                        }
467 45772 omartinez
                    }
468
                    values[n++] = new DynObjectValueItem(code, Objects.toString(value, Objects.toString(code, "##ERROR##")));
469
                    if (n >= MAX_AVAILABLE_VALUES) {
470
                        break;
471
                    }
472
                }
473
                this.availableValues = values;
474
475
            } catch (Exception ex) {
476
                LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.getCodeName() + "' from table '" + this.getTableName() + "'.", ex);
477
            } finally {
478 45946 omartinez
                this.loadAvailableValues = false;
479 45772 omartinez
                DisposeUtils.disposeQuietly(set);
480 45946 omartinez
                DisposeUtils.disposeQuietly(foreingStore);
481 45739 jjdelcerro
            }
482 44262 jjdelcerro
        }
483 44338 jjdelcerro
        return this.availableValues;
484 44262 jjdelcerro
    }
485 44338 jjdelcerro
486 45772 omartinez
    private String getStoreName() {
487
        if (this.descriptor==null) {
488
            return "Unknown";
489
        }
490
        return this.descriptor.getStore().getName();
491
    }
492
493 44363 jjdelcerro
    @Override
494 44338 jjdelcerro
    public String getLabelForValue(Object value) {
495
        DynObjectValueItem[] values = this.getAvailableValues(null);
496 45772 omartinez
        if (values != null) {
497 44338 jjdelcerro
            for (DynObjectValueItem value1 : values) {
498 45772 omartinez
                if (Objects.equals(value, value1.getValue())) {
499 44338 jjdelcerro
                    return value1.getLabel();
500
                }
501
            }
502
        }
503
        return Objects.toString(value, "##ERROR##");
504
    }
505 44262 jjdelcerro
506
    @Override
507
    public void loadFromState(PersistentState state)
508
            throws PersistenceException {
509
        foreingKey = state.getBoolean("foreingKey");
510 44338 jjdelcerro
        closedList = state.getBoolean("selectable");
511 44262 jjdelcerro
        labelFormula = state.getString("labelFormula");
512
        codeName = state.getString("codeName");
513
        tableName = state.getString("tableName");
514 44363 jjdelcerro
        ensureReferentialIntegrity = state.getBoolean("ensureReferentialIntegrity");
515 44262 jjdelcerro
    }
516
517
    @Override
518
    public void saveToState(PersistentState state) throws PersistenceException {
519
        state.set("foreingKey", foreingKey);
520 44338 jjdelcerro
        state.set("selectable", closedList);
521 44262 jjdelcerro
        state.set("labelFormula", labelFormula);
522
        state.set("codeName", codeName);
523
        state.set("tableName", tableName);
524 44363 jjdelcerro
        state.set("ensureReferentialIntegrity", ensureReferentialIntegrity);
525 44262 jjdelcerro
    }
526
527
    private static final String FOREINGKEY_PERSISTENCE_DEFINITION_NAME = "ForeingKey";
528
529
    public static void registerPersistenceDefinition() {
530
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
531
532
        if (manager.getDefinition(FOREINGKEY_PERSISTENCE_DEFINITION_NAME)
533
                == null) {
534
            DynStruct definition = manager.addDefinition(DefaultForeingKey.class,
535
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME,
536
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME
537
                    + " persistent definition",
538
                    null,
539
                    null
540
            );
541
            definition.addDynFieldBoolean("foreingKey");
542
            definition.addDynFieldBoolean("selectable");
543
            definition.addDynFieldString("LabelFormula");
544
            definition.addDynFieldString("codeName");
545
            definition.addDynFieldString("tableName");
546 44363 jjdelcerro
            definition.addDynFieldBoolean("ensureReferentialIntegrity");
547 44262 jjdelcerro
        }
548
    }
549
550
    @Override
551
    public ForeingKey clone() throws CloneNotSupportedException {
552
        DefaultForeingKey other = (DefaultForeingKey) super.clone();
553
        return other;
554
    }
555
556 44363 jjdelcerro
    @Override
557
    public boolean getEnsureReferentialIntegrity() {
558
        return this.ensureReferentialIntegrity;
559
    }
560
561
    @Override
562
    public void setEnsureReferentialIntegrity(boolean ensureReferentialIntegrity) {
563
        this.ensureReferentialIntegrity = ensureReferentialIntegrity;
564
    }
565 45772 omartinez
566 45258 omartinez
    @Override
567
    public boolean isInAvailableValues(Object valueToCheck) {
568
        if (this.hasAvailableValues() && availableValues.length > 0) {
569
            for (DynObjectValueItem availableValue : availableValues) {
570
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
571
                    return true;
572
                }
573
            }
574
        }
575
        return false;
576
    }
577
578
    @Override
579
    public boolean hasAvailableValues() {
580 45772 omartinez
        if (this.availableValues == null) {
581 45258 omartinez
            this.getAvailableValues(null);
582
        }
583
        return this.availableValues != null;
584
    }
585 45772 omartinez
586 44262 jjdelcerro
}