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

History | View | Annotate | Download (18.7 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.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
import org.gvsig.fmap.dal.feature.FeatureSet;
22
import org.gvsig.fmap.dal.feature.FeatureStore;
23
import org.gvsig.fmap.dal.feature.FeatureType;
24
import static org.gvsig.fmap.dal.feature.ForeingKey.MAX_AVAILABLE_VALUES;
25
import org.gvsig.tools.ToolsLocator;
26
import org.gvsig.tools.dispose.DisposeUtils;
27
import org.gvsig.tools.dynobject.DynObject;
28
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
        private DynObject contextValues;
54
        private int refs;
55

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

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

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

    
69
        @Override
70
        public void dispose() {
71
            DisposeUtils.disposeQuietly(featureStore);
72
            DisposeUtils.disposeQuietly(contextValues);
73
            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
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
84
            }
85
            return this.storesRepository;
86
        }
87

    
88
        @Override
89
        public FeatureStore getFeatureStore() {
90
            if (this.featureStore == null) {
91
                StoresRepository repository = this.getStoresRepository();
92
                this.featureStore = (FeatureStore) repository.getStore(tableName);
93
                if (this.featureStore == null) {
94
                    LOGGER.warn("Can't locate store '" + tableName + "' to get available values.");
95
                    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

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

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

    
143
    private boolean foreingKey;
144
    private boolean closedList;
145
    private String labelFormula;
146
    private String tableName;
147
    private String codeName;
148
    private DynObjectValueItem[] availableValues;
149
    private boolean ensureReferentialIntegrity;
150
    private StoresRepository storesRepository = null;
151
    private FeatureAttributeDescriptor descriptor;
152

    
153
    public DefaultForeingKey() {
154
        this.foreingKey = false;
155
        this.closedList = false;
156
        this.tableName = null;
157
        this.codeName = null;
158
        this.labelFormula = null;
159
        this.ensureReferentialIntegrity = false;
160
    }
161

    
162
    public void setDescriptor(FeatureAttributeDescriptor descriptor) {
163
        this.descriptor = descriptor;
164
    }
165
    
166
    private StoresRepository getStoresRepository() {
167
        if( this.descriptor == null ) {
168
            this.storesRepository = DALLocator.getDataManager().getStoresRepository();
169
        } else {
170
            FeatureStore store = descriptor.getStore();
171
            if( store==null ) {
172
                this.storesRepository = DALLocator.getDataManager().getStoresRepository();
173
            } else {
174
                this.storesRepository = store.getStoresRepository();
175
            }
176
        }
177
        return this.storesRepository;
178
    }
179
    
180
    @Override
181
    public void unbind() {
182
        this.getStoresRepository(); // Force get stores repository
183
        this.descriptor = null;
184
        this.availableValues = null;
185
    }
186

    
187
    @Override
188
    public boolean isClosedList() {
189
        return this.closedList;
190
    }
191

    
192
    @Override
193
    public void setClosedList(boolean selectable) {
194
        this.closedList = selectable;
195
    }
196

    
197
    @Override
198
    public boolean isForeingKey() {
199
        return this.foreingKey;
200
    }
201

    
202
    @Override
203
    public void setForeingKey(boolean foreingKey) {
204
        this.foreingKey = foreingKey;
205
    }
206

    
207
    @Override
208
    public String getLabelFormula() {
209
        return this.labelFormula;
210
    }
211

    
212
    @Override
213
    public void setLabelFormula(String labelFormula) {
214
        this.labelFormula = labelFormula;
215
    }
216

    
217
    @Override
218
    public String getCodeName() {
219
        return this.codeName;
220
    }
221

    
222
    @Override
223
    public void setCodeName(String codeName) {
224
        this.codeName = codeName;
225
    }
226

    
227
    @Override
228
    public String getTableName() {
229
        return this.tableName;
230
    }
231

    
232
    @Override
233
    public void setTableName(String tableName) {
234
        this.tableName = tableName;
235
    }
236

    
237
    @Override
238
    public boolean isEmpty() {
239
        if (!this.foreingKey
240
                && !this.closedList
241
                && StringUtils.isBlank(this.tableName)
242
                && StringUtils.isBlank(this.codeName)
243
                && StringUtils.isBlank(this.labelFormula)) {
244
            return true;
245
        }
246
        return false;
247
    }
248

    
249
    @Override
250
    public void clean() {
251
        this.foreingKey = false;
252
        this.closedList = false;
253
        this.tableName = null;
254
        this.codeName = null;
255
        this.labelFormula = null;
256
        this.ensureReferentialIntegrity = false;
257
    }
258

    
259
    private void disposeIfLocalContext(ContextForeingKey context) {
260
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
261
        c.relese();
262
        if (c.refs == 0) {
263
            context.dispose();
264
        }
265
    }
266

    
267
    private ContextForeingKey createLocalContextIfNull(ContextForeingKey context) {
268
        if (context == null) {
269
            return createContext();
270
        }
271
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
272
        c.addRef();
273
        return c;
274
    }
275

    
276
    @Override
277
    public ContextForeingKey createContext() {
278
        return new DefaultContextForeingKey(this.getStoresRepository());
279
    }
280

    
281
    @Override
282
    public StoresRepository getStoresRepository(ContextForeingKey context) {
283
        context = createLocalContextIfNull(context);
284
        try {
285
            return context.getStoresRepository();
286
        } finally {
287
            disposeIfLocalContext(context);
288
        }
289
    }
290

    
291
    @Override
292
    public FeatureStore getFeatureStore(ContextForeingKey context) {
293
        context = createLocalContextIfNull(context);
294
        try {
295
            return context.getFeatureStore();
296
        } finally {
297
            disposeIfLocalContext(context);
298
        }
299
    }
300

    
301
    @Override
302
    public FeatureType getFeatureType(ContextForeingKey context) {
303
        context = createLocalContextIfNull(context);
304
        FeatureStore store = context.getFeatureStore();
305
        if (store == null) {
306
            return null;
307
        }
308
        try {
309
            return store.getDefaultFeatureType();
310
        } catch (DataException ex) {
311
            return null;
312
        } finally {
313
            disposeIfLocalContext(context);
314
        }
315
    }
316

    
317
    @Override
318
    public List<Feature> getFeatures(ContextForeingKey context) {
319
        context = createLocalContextIfNull(context);
320
        FeatureStore store = context.getFeatureStore();
321
        if (store == null) {
322
            return null;
323
        }
324
        try {
325
            return store.getFeatures();
326
        } finally {
327
            disposeIfLocalContext(context);
328
        }
329
    }
330

    
331
    @Override
332
    public Object getCode(ContextForeingKey context, Feature feature) {
333
//        context = createLocalContextIfNull(context);
334
        try {
335
            return feature.get(codeName);
336
        } finally {
337
//            disposeIfLocalContext(context);
338
        }
339
    }
340

    
341
    @Override
342
    public FeatureQuery getQuery(ContextForeingKey context, Object codeValue) {
343
        context = createLocalContextIfNull(context);
344
        try {
345
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
346
            FeatureStore store = context.getFeatureStore();
347
            FeatureQuery query = store.createFeatureQuery();
348
            query.setFilter(builder.eq(
349
                    builder.variable(codeName),
350
                    builder.constant(codeValue)
351
            ).toString()
352
            );
353
            query.retrievesAllAttributes();
354
            return query;
355
        } finally {
356
            disposeIfLocalContext(context);
357
        }
358
    }
359

    
360
    @Override
361
    public Feature getFeature(ContextForeingKey context, Object codeValue) {
362
        context = createLocalContextIfNull(context);
363
        try {
364
            FeatureStore store = context.getFeatureStore();
365
            if (store == null) {
366
                return null;
367
            }
368
            FeatureQuery query = this.getQuery(context, codeValue);
369
            Feature feature = store.findFirst(query);
370
            return feature;
371
        } catch (DataException ex) {
372
            return null;
373
        } finally {
374
            disposeIfLocalContext(context);
375
        }
376
    }
377

    
378
    @Override
379
    public String getLabel(ContextForeingKey context, Object codeValue) {
380
        context = createLocalContextIfNull(context);
381
        try {
382
            Feature feature = this.getFeature(context, codeValue);
383
            if (feature == null) {
384
                return null;
385
            }
386
            return getLabel(context, feature);
387
        } finally {
388
            disposeIfLocalContext(context);
389
        }
390
    }
391

    
392
    @Override
393
    public Expression getLabelExpression(ContextForeingKey context) {
394
        context = createLocalContextIfNull(context);
395
        try {
396
            return context.getLabelExpression();
397
        } finally {
398
            disposeIfLocalContext(context);
399
        }
400
    }
401

    
402
    @Override
403
    public String getLabel(ContextForeingKey context, Feature feature) {
404
        if (feature == null) {
405
            return null;
406
        }
407
        context = createLocalContextIfNull(context);
408
        try {
409
            Expression labelExpression = context.getLabelExpression();
410
            if (labelExpression == null) {
411
                return feature.toString();
412
            }
413
            context.getFeatureSymbolTable().setFeature(feature);
414
            Object x = labelExpression.execute(context.getSymbolTable());
415
            if (x == null) {
416
                return null;
417
            }
418
            return x.toString();
419
        } finally {
420
            disposeIfLocalContext(context);
421
        }
422
    }
423

    
424
    @Override
425
    public DynObjectValueItem[] getAvailableValues(ContextForeingKey context) {
426
        if (!this.isClosedList()) {
427
            return null;
428
        }
429
        if (this.availableValues == null) {
430

    
431
            FeatureStore foreingStore = null;
432
            FeatureSet.DisposableFeatureSetIterable set = null;
433

    
434
            try {
435

    
436
                StoresRepository theStoresRepository = this.getStoresRepository(context);
437

    
438
                foreingStore = (FeatureStore) theStoresRepository.getStore(
439
                        this.getTableName()
440
                );
441
                Expression labelExpression = this.getLabelExpression(null);
442
                String theCodeName =  this.getCodeName();
443
                FeatureSymbolTable featureSymbolTable = DALLocator.getDataManager().createFeatureSymbolTable();
444
                MutableSymbolTable symbolTable = featureSymbolTable.createParent();
445

    
446
                int count = (int) foreingStore.getFeatureCount();
447
                DynObjectValueItem[] values = new DynObjectValueItem[Math.min(count, MAX_AVAILABLE_VALUES)];
448
                int n = 0;
449
                for (Feature feature : set = foreingStore.getFeatureSet().iterable()) {
450
                    Object code = feature.get(theCodeName);
451
                    Object value;
452
                    if (labelExpression == null) {
453
                        value = code;
454
                    } else {
455
                        featureSymbolTable.setFeature(feature);
456
                        value = labelExpression.execute(symbolTable);
457
                    }
458
                    values[n++] = new DynObjectValueItem(code, Objects.toString(value, Objects.toString(code, "##ERROR##")));
459
                    if (n >= MAX_AVAILABLE_VALUES) {
460
                        break;
461
                    }
462
                }
463
                this.availableValues = values;
464

    
465
            } catch (Exception ex) {
466
                LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.getCodeName() + "' from table '" + this.getTableName() + "'.", ex);
467
            } finally {
468
                DisposeUtils.disposeQuietly(set);
469
                DisposeUtils.disposeQuietly(foreingStore);
470
            }
471
        }
472
        return this.availableValues;
473
    }
474
    
475
    private String getStoreName() {
476
        if (this.descriptor==null) {
477
            return "Unknown";
478
        }
479
        return this.descriptor.getStore().getName();
480
    }
481

    
482
    @Override
483
    public String getLabelForValue(Object value) {
484
        DynObjectValueItem[] values = this.getAvailableValues(null);
485
        if (values != null) {
486
            for (DynObjectValueItem value1 : values) {
487
                if (Objects.equals(value, value1.getValue())) {
488
                    return value1.getLabel();
489
                }
490
            }
491
        }
492
        return Objects.toString(value, "##ERROR##");
493
    }
494

    
495
    @Override
496
    public void loadFromState(PersistentState state)
497
            throws PersistenceException {
498
        foreingKey = state.getBoolean("foreingKey");
499
        closedList = state.getBoolean("selectable");
500
        labelFormula = state.getString("labelFormula");
501
        codeName = state.getString("codeName");
502
        tableName = state.getString("tableName");
503
        ensureReferentialIntegrity = state.getBoolean("ensureReferentialIntegrity");
504
    }
505

    
506
    @Override
507
    public void saveToState(PersistentState state) throws PersistenceException {
508
        state.set("foreingKey", foreingKey);
509
        state.set("selectable", closedList);
510
        state.set("labelFormula", labelFormula);
511
        state.set("codeName", codeName);
512
        state.set("tableName", tableName);
513
        state.set("ensureReferentialIntegrity", ensureReferentialIntegrity);
514
    }
515

    
516
    private static final String FOREINGKEY_PERSISTENCE_DEFINITION_NAME = "ForeingKey";
517

    
518
    public static void registerPersistenceDefinition() {
519
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
520

    
521
        if (manager.getDefinition(FOREINGKEY_PERSISTENCE_DEFINITION_NAME)
522
                == null) {
523
            DynStruct definition = manager.addDefinition(DefaultForeingKey.class,
524
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME,
525
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME
526
                    + " persistent definition",
527
                    null,
528
                    null
529
            );
530
            definition.addDynFieldBoolean("foreingKey");
531
            definition.addDynFieldBoolean("selectable");
532
            definition.addDynFieldString("LabelFormula");
533
            definition.addDynFieldString("codeName");
534
            definition.addDynFieldString("tableName");
535
            definition.addDynFieldBoolean("ensureReferentialIntegrity");
536
        }
537
    }
538

    
539
    @Override
540
    public ForeingKey clone() throws CloneNotSupportedException {
541
        DefaultForeingKey other = (DefaultForeingKey) super.clone();
542
        return other;
543
    }
544

    
545
    @Override
546
    public boolean getEnsureReferentialIntegrity() {
547
        return this.ensureReferentialIntegrity;
548
    }
549

    
550
    @Override
551
    public void setEnsureReferentialIntegrity(boolean ensureReferentialIntegrity) {
552
        this.ensureReferentialIntegrity = ensureReferentialIntegrity;
553
    }
554

    
555
    @Override
556
    public boolean isInAvailableValues(Object valueToCheck) {
557
        if (this.hasAvailableValues() && availableValues.length > 0) {
558
            for (DynObjectValueItem availableValue : availableValues) {
559
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
560
                    return true;
561
                }
562
            }
563
        }
564
        return false;
565
    }
566

    
567
    @Override
568
    public boolean hasAvailableValues() {
569
        if (this.availableValues == null) {
570
            this.getAvailableValues(null);
571
        }
572
        return this.availableValues != null;
573
    }
574

    
575
}