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

History | View | Annotate | Download (18.3 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
        FeatureStore store = descriptor.getStore();
165
        if (store == null) {
166
            this.storesRepository = DALLocator.getDataManager().getStoresRepository();
167

    
168
        } else {
169
            this.storesRepository = store.getStoresRepository();
170
        }
171
    }
172
    
173
    public void unbind() {
174
        this.descriptor = null;
175
        this.availableValues = null;
176
    }
177

    
178
    @Override
179
    public boolean isClosedList() {
180
        return this.closedList;
181
    }
182

    
183
    @Override
184
    public void setClosedList(boolean selectable) {
185
        this.closedList = selectable;
186
    }
187

    
188
    @Override
189
    public boolean isForeingKey() {
190
        return this.foreingKey;
191
    }
192

    
193
    @Override
194
    public void setForeingKey(boolean foreingKey) {
195
        this.foreingKey = foreingKey;
196
    }
197

    
198
    @Override
199
    public String getLabelFormula() {
200
        return this.labelFormula;
201
    }
202

    
203
    @Override
204
    public void setLabelFormula(String labelFormula) {
205
        this.labelFormula = labelFormula;
206
    }
207

    
208
    @Override
209
    public String getCodeName() {
210
        return this.codeName;
211
    }
212

    
213
    @Override
214
    public void setCodeName(String codeName) {
215
        this.codeName = codeName;
216
    }
217

    
218
    @Override
219
    public String getTableName() {
220
        return this.tableName;
221
    }
222

    
223
    @Override
224
    public void setTableName(String tableName) {
225
        this.tableName = tableName;
226
    }
227

    
228
    @Override
229
    public boolean isEmpty() {
230
        if (!this.foreingKey
231
                && !this.closedList
232
                && StringUtils.isBlank(this.tableName)
233
                && StringUtils.isBlank(this.codeName)
234
                && StringUtils.isBlank(this.labelFormula)) {
235
            return true;
236
        }
237
        return false;
238
    }
239

    
240
    @Override
241
    public void clean() {
242
        this.foreingKey = false;
243
        this.closedList = false;
244
        this.tableName = null;
245
        this.codeName = null;
246
        this.labelFormula = null;
247
        this.ensureReferentialIntegrity = false;
248
    }
249

    
250
    private void disposeIfLocalContext(ContextForeingKey context) {
251
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
252
        c.relese();
253
        if (c.refs == 0) {
254
            context.dispose();
255
        }
256
    }
257

    
258
    private ContextForeingKey createLocalContextIfNull(ContextForeingKey context) {
259
        if (context == null) {
260
            return createContext();
261
        }
262
        DefaultContextForeingKey c = (DefaultContextForeingKey) context;
263
        c.addRef();
264
        return c;
265
    }
266

    
267
    @Override
268
    public ContextForeingKey createContext() {
269
        return new DefaultContextForeingKey(this.storesRepository);
270
    }
271

    
272
    @Override
273
    public StoresRepository getStoresRepository(ContextForeingKey context) {
274
        context = createLocalContextIfNull(context);
275
        try {
276
            return context.getStoresRepository();
277
        } finally {
278
            disposeIfLocalContext(context);
279
        }
280
    }
281

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

    
292
    @Override
293
    public FeatureType getFeatureType(ContextForeingKey context) {
294
        context = createLocalContextIfNull(context);
295
        FeatureStore store = context.getFeatureStore();
296
        if (store == null) {
297
            return null;
298
        }
299
        try {
300
            return store.getDefaultFeatureType();
301
        } catch (DataException ex) {
302
            return null;
303
        } finally {
304
            disposeIfLocalContext(context);
305
        }
306
    }
307

    
308
    @Override
309
    public List<Feature> getFeatures(ContextForeingKey context) {
310
        context = createLocalContextIfNull(context);
311
        FeatureStore store = context.getFeatureStore();
312
        if (store == null) {
313
            return null;
314
        }
315
        try {
316
            return store.getFeatures();
317
        } finally {
318
            disposeIfLocalContext(context);
319
        }
320
    }
321

    
322
    @Override
323
    public Object getCode(ContextForeingKey context, Feature feature) {
324
//        context = createLocalContextIfNull(context);
325
        try {
326
            return feature.get(codeName);
327
        } finally {
328
//            disposeIfLocalContext(context);
329
        }
330
    }
331

    
332
    @Override
333
    public FeatureQuery getQuery(ContextForeingKey context, Object codeValue) {
334
        context = createLocalContextIfNull(context);
335
        try {
336
            ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
337
            FeatureStore store = context.getFeatureStore();
338
            FeatureQuery query = store.createFeatureQuery();
339
            query.setFilter(builder.eq(
340
                    builder.variable(codeName),
341
                    builder.constant(codeValue)
342
            ).toString()
343
            );
344
            query.retrievesAllAttributes();
345
            return query;
346
        } finally {
347
            disposeIfLocalContext(context);
348
        }
349
    }
350

    
351
    @Override
352
    public Feature getFeature(ContextForeingKey context, Object codeValue) {
353
        context = createLocalContextIfNull(context);
354
        try {
355
            FeatureStore store = context.getFeatureStore();
356
            if (store == null) {
357
                return null;
358
            }
359
            FeatureQuery query = this.getQuery(context, codeValue);
360
            Feature feature = store.findFirst(query);
361
            return feature;
362
        } catch (DataException ex) {
363
            return null;
364
        } finally {
365
            disposeIfLocalContext(context);
366
        }
367
    }
368

    
369
    @Override
370
    public String getLabel(ContextForeingKey context, Object codeValue) {
371
        context = createLocalContextIfNull(context);
372
        try {
373
            Feature feature = this.getFeature(context, codeValue);
374
            if (feature == null) {
375
                return null;
376
            }
377
            return getLabel(context, feature);
378
        } finally {
379
            disposeIfLocalContext(context);
380
        }
381
    }
382

    
383
    @Override
384
    public Expression getLabelExpression(ContextForeingKey context) {
385
        context = createLocalContextIfNull(context);
386
        try {
387
            return context.getLabelExpression();
388
        } finally {
389
            disposeIfLocalContext(context);
390
        }
391
    }
392

    
393
    @Override
394
    public String getLabel(ContextForeingKey context, Feature feature) {
395
        if (feature == null) {
396
            return null;
397
        }
398
        context = createLocalContextIfNull(context);
399
        try {
400
            Expression labelExpression = context.getLabelExpression();
401
            if (labelExpression == null) {
402
                return feature.toString();
403
            }
404
            context.getFeatureSymbolTable().setFeature(feature);
405
            Object x = labelExpression.execute(context.getSymbolTable());
406
            if (x == null) {
407
                return null;
408
            }
409
            return x.toString();
410
        } finally {
411
            disposeIfLocalContext(context);
412
        }
413
    }
414

    
415
    @Override
416
    public DynObjectValueItem[] getAvailableValues(ContextForeingKey context) {
417
        if (!this.isClosedList()) {
418
            return null;
419
        }
420
        if (this.availableValues == null) {
421

    
422
            FeatureStore foreingStore = null;
423
            FeatureSet.DisposableFeatureSetIterable set = null;
424

    
425
            try {
426

    
427
                StoresRepository theStoresRepository = this.getStoresRepository(context);
428

    
429
                foreingStore = (FeatureStore) theStoresRepository.getStore(
430
                        this.getTableName()
431
                );
432
                Expression labelExpression = this.getLabelExpression(null);
433
                String theCodeName =  this.getCodeName();
434
                FeatureSymbolTable featureSymbolTable = DALLocator.getDataManager().createFeatureSymbolTable();
435
                MutableSymbolTable symbolTable = featureSymbolTable.createParent();
436

    
437
                int count = (int) foreingStore.getFeatureCount();
438
                DynObjectValueItem[] values = new DynObjectValueItem[Math.min(count, MAX_AVAILABLE_VALUES)];
439
                int n = 0;
440
                for (Feature feature : set = foreingStore.getFeatureSet().iterable()) {
441
                    Object code = feature.get(theCodeName);
442
                    Object value;
443
                    if (labelExpression == null) {
444
                        value = code;
445
                    } else {
446
                        featureSymbolTable.setFeature(feature);
447
                        value = labelExpression.execute(symbolTable);
448
                    }
449
                    values[n++] = new DynObjectValueItem(code, Objects.toString(value, Objects.toString(code, "##ERROR##")));
450
                    if (n >= MAX_AVAILABLE_VALUES) {
451
                        break;
452
                    }
453
                }
454
                this.availableValues = values;
455

    
456
            } catch (Exception ex) {
457
                LOGGER.warn("Can't get available values for field '" + this.getStoreName() + "." + this.getCodeName() + "' from table '" + this.getTableName() + "'.", ex);
458
            } finally {
459
                DisposeUtils.disposeQuietly(set);
460
                DisposeUtils.disposeQuietly(foreingStore);
461
            }
462
        }
463
        return this.availableValues;
464
    }
465
    
466
    private String getStoreName() {
467
        if (this.descriptor==null) {
468
            return "Unknown";
469
        }
470
        return this.descriptor.getStore().getName();
471
    }
472

    
473
    @Override
474
    public String getLabelForValue(Object value) {
475
        DynObjectValueItem[] values = this.getAvailableValues(null);
476
        if (values != null) {
477
            for (DynObjectValueItem value1 : values) {
478
                if (Objects.equals(value, value1.getValue())) {
479
                    return value1.getLabel();
480
                }
481
            }
482
        }
483
        return Objects.toString(value, "##ERROR##");
484
    }
485

    
486
    @Override
487
    public void loadFromState(PersistentState state)
488
            throws PersistenceException {
489
        foreingKey = state.getBoolean("foreingKey");
490
        closedList = state.getBoolean("selectable");
491
        labelFormula = state.getString("labelFormula");
492
        codeName = state.getString("codeName");
493
        tableName = state.getString("tableName");
494
        ensureReferentialIntegrity = state.getBoolean("ensureReferentialIntegrity");
495
    }
496

    
497
    @Override
498
    public void saveToState(PersistentState state) throws PersistenceException {
499
        state.set("foreingKey", foreingKey);
500
        state.set("selectable", closedList);
501
        state.set("labelFormula", labelFormula);
502
        state.set("codeName", codeName);
503
        state.set("tableName", tableName);
504
        state.set("ensureReferentialIntegrity", ensureReferentialIntegrity);
505
    }
506

    
507
    private static final String FOREINGKEY_PERSISTENCE_DEFINITION_NAME = "ForeingKey";
508

    
509
    public static void registerPersistenceDefinition() {
510
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
511

    
512
        if (manager.getDefinition(FOREINGKEY_PERSISTENCE_DEFINITION_NAME)
513
                == null) {
514
            DynStruct definition = manager.addDefinition(DefaultForeingKey.class,
515
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME,
516
                    FOREINGKEY_PERSISTENCE_DEFINITION_NAME
517
                    + " persistent definition",
518
                    null,
519
                    null
520
            );
521
            definition.addDynFieldBoolean("foreingKey");
522
            definition.addDynFieldBoolean("selectable");
523
            definition.addDynFieldString("LabelFormula");
524
            definition.addDynFieldString("codeName");
525
            definition.addDynFieldString("tableName");
526
            definition.addDynFieldBoolean("ensureReferentialIntegrity");
527
        }
528
    }
529

    
530
    @Override
531
    public ForeingKey clone() throws CloneNotSupportedException {
532
        DefaultForeingKey other = (DefaultForeingKey) super.clone();
533
        return other;
534
    }
535

    
536
    @Override
537
    public boolean getEnsureReferentialIntegrity() {
538
        return this.ensureReferentialIntegrity;
539
    }
540

    
541
    @Override
542
    public void setEnsureReferentialIntegrity(boolean ensureReferentialIntegrity) {
543
        this.ensureReferentialIntegrity = ensureReferentialIntegrity;
544
    }
545

    
546
    @Override
547
    public boolean isInAvailableValues(Object valueToCheck) {
548
        if (this.hasAvailableValues() && availableValues.length > 0) {
549
            for (DynObjectValueItem availableValue : availableValues) {
550
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
551
                    return true;
552
                }
553
            }
554
        }
555
        return false;
556
    }
557

    
558
    @Override
559
    public boolean hasAvailableValues() {
560
        if (this.availableValues == null) {
561
            this.getAvailableValues(null);
562
        }
563
        return this.availableValues != null;
564
    }
565

    
566
}