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 / DefaultFeatureAttributeDescriptor.java @ 44448

History | View | Annotate | Download (41.8 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 3 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.fmap.dal.feature.impl;
24

    
25
import java.lang.ref.WeakReference;
26
import java.text.DateFormat;
27
import java.util.HashMap;
28
import java.util.Iterator;
29
import java.util.LinkedHashMap;
30
import java.util.List;
31
import java.util.Map;
32
import java.util.Map.Entry;
33
import java.util.Objects;
34
import org.apache.commons.lang3.ArrayUtils;
35
import org.apache.commons.lang3.StringUtils;
36
import org.cresques.cts.IProjection;
37
import org.gvsig.fmap.dal.DALLocator;
38
import org.gvsig.fmap.dal.DataStore;
39
import org.gvsig.fmap.dal.DataTypes;
40
import org.gvsig.fmap.dal.feature.DataProfile;
41
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
42
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
43
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
44
import org.gvsig.fmap.dal.feature.FeatureStore;
45
import org.gvsig.fmap.dal.feature.FeatureType;
46
import org.gvsig.fmap.dal.feature.ForeingKey;
47
import org.gvsig.fmap.geom.Geometry;
48
import org.gvsig.fmap.geom.GeometryException;
49
import org.gvsig.fmap.geom.GeometryLocator;
50
import org.gvsig.fmap.geom.GeometryUtils;
51
import org.gvsig.fmap.geom.type.GeometryType;
52
import org.gvsig.timesupport.Interval;
53
import org.gvsig.timesupport.RelativeInterval;
54
import org.gvsig.timesupport.TimeSupportLocator;
55
import org.gvsig.tools.ToolsLocator;
56
import org.gvsig.tools.dataTypes.CoercionException;
57
import org.gvsig.tools.dataTypes.DataType;
58
import org.gvsig.tools.dynobject.DynField;
59
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
60
import org.gvsig.tools.dynobject.DynField_v2;
61
import org.gvsig.tools.dynobject.DynMethod;
62
import org.gvsig.tools.dynobject.DynObject;
63
import org.gvsig.tools.dynobject.DynObjectValueItem;
64
import org.gvsig.tools.dynobject.DynStruct;
65
import org.gvsig.tools.dynobject.Tags;
66
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
67
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
68
import org.gvsig.tools.dynobject.exception.DynMethodException;
69
import org.gvsig.tools.dynobject.impl.DefaultTags;
70
import org.gvsig.tools.evaluator.AbstractEvaluator;
71
import org.gvsig.tools.evaluator.Evaluator;
72
import org.gvsig.tools.evaluator.EvaluatorData;
73
import org.gvsig.tools.evaluator.EvaluatorException;
74
import org.gvsig.tools.i18n.I18nManager;
75
import org.gvsig.tools.persistence.PersistenceManager;
76
import org.gvsig.tools.persistence.Persistent;
77
import org.gvsig.tools.persistence.PersistentState;
78
import org.gvsig.tools.persistence.exception.PersistenceException;
79
import org.slf4j.Logger;
80
import org.slf4j.LoggerFactory;
81

    
82
@SuppressWarnings("UseSpecificCatch")
83
public class DefaultFeatureAttributeDescriptor implements
84
        FeatureAttributeDescriptor, Persistent, DynField_v2, DynField_LabelAttribute {
85

    
86
    protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureAttributeDescriptor.class);
87
    
88
    protected boolean allowNull;
89
    protected DataType dataType;
90
    protected String dataProfile; 
91
    protected DateFormat dateFormat;
92
    protected Object defaultValue;
93
    protected int index;
94
    protected int maximumOccurrences;
95
    protected int minimumOccurrences;
96
    protected int size;
97
    protected String name;
98
    protected Class objectClass;
99
    protected int precision;
100
    protected Evaluator evaluator;
101
    protected boolean primaryKey;
102
    protected boolean readOnly;
103
    protected IProjection SRS;
104
    protected GeometryType geomType;
105
    protected int geometryType;
106
    protected int geometrySubType;
107
    protected Map additionalInfo;
108
    protected boolean isAutomatic;
109
    protected boolean isTime = false;
110
    protected Interval interval;
111
    protected FeatureAttributeGetter featureAttributeGetter = null;
112
    protected FeatureAttributeEmulator featureAttributeEmulator = null;
113
    protected boolean indexed = false;
114
    protected boolean isIndexAscending = true;
115
    protected boolean allowIndexDuplicateds = true;
116

    
117
    protected DynObjectValueItem[] availableValues;
118
    private Map<Object,String> labelOfValueMap; // No persistente
119
    protected String description;
120
    protected Object minValue;
121
    protected Object maxValue;
122
    protected String label;
123
    protected String shortLabel;
124
    protected int order;
125
    protected boolean hidden;
126
    protected String groupName;
127
    protected Tags tags = new DefaultTags();
128
    private DynMethod availableValuesMethod;
129
    private DynMethod calculateMethod;
130
    private WeakReference typeRef;
131
    protected DefaultForeingKey foreingKey = null;
132
    
133
    private int relationType = RELATION_TYPE_NONE;
134

    
135
    public DefaultFeatureAttributeDescriptor() {
136
        // Usada en la persistencia
137
    }
138

    
139
    protected DefaultFeatureAttributeDescriptor(FeatureType type) {
140
        this();
141
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x].", this.hashCode()));
142
        setFeatureType(type);
143
        this.allowNull = true;
144
        this.dataType = null;
145
        this.dateFormat = null;
146
        this.defaultValue = null;
147
        this.index = -1;
148
        this.maximumOccurrences = 0;
149
        this.minimumOccurrences = 0;
150
        this.size = 0;
151
        this.name = null;
152
        this.objectClass = null;
153
        this.precision = 0;
154
        this.evaluator = null;
155
        this.primaryKey = false;
156
        this.readOnly = false;
157
        this.SRS = null;
158
        this.geometryType = Geometry.TYPES.NULL;
159
        this.geometrySubType = Geometry.SUBTYPES.UNKNOWN;
160
        this.additionalInfo = null;
161
        this.isAutomatic = false;
162
        this.hidden = false;
163
        this.relationType = RELATION_TYPE_NONE;
164
    }
165

    
166
    protected DefaultFeatureAttributeDescriptor(
167
            DefaultFeatureAttributeDescriptor other
168
        ) {
169
        this();
170
        copyFrom(other);
171
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x] [%s] (copy).", this.hashCode(), this.name));
172
    }
173
    
174
    @Override
175
    public void copyFrom(DynField other1) {
176
        if( !(other1 instanceof DefaultFeatureAttributeDescriptor) ) {
177
            throw new IllegalArgumentException("Can't copy from a non DefaultFeatureAttributeDescriptor");
178
        }
179
        DefaultFeatureAttributeDescriptor other = (DefaultFeatureAttributeDescriptor) other1;
180
        this.typeRef = other.typeRef;
181
        this.allowNull = other.allowNull;
182
        this.dataType = other.dataType;
183
        this.dateFormat = other.dateFormat;
184
        this.defaultValue = other.defaultValue;
185
        this.index = other.index;
186
        this.maximumOccurrences = other.maximumOccurrences;
187
        this.minimumOccurrences = other.minimumOccurrences;
188
        this.size = other.size;
189
        this.name = other.name;
190
        this.objectClass = other.objectClass;
191
        this.precision = other.precision;
192
        this.evaluator = other.evaluator;
193
        this.primaryKey = other.primaryKey;
194
        this.readOnly = other.readOnly;
195
        this.SRS = other.SRS;
196
        this.geometryType = other.geometryType;
197
        this.geometrySubType = other.geometrySubType;
198
        this.geomType = other.geomType;
199
        if (other.additionalInfo != null) {
200
            Iterator iter = other.additionalInfo.entrySet().iterator();
201
            Map.Entry entry;
202
            this.additionalInfo = new HashMap();
203
            while (iter.hasNext()) {
204
                entry = (Entry) iter.next();
205
                this.additionalInfo.put(entry.getKey(), entry.getValue());
206
            }
207
        } else {
208
            this.additionalInfo = null;
209
        }
210
        this.isAutomatic = other.isAutomatic;
211
        this.isTime = other.isTime;
212
        this.featureAttributeEmulator = other.featureAttributeEmulator;
213
        this.indexed = other.indexed;
214
        this.isIndexAscending = other.isIndexAscending;
215
        this.allowIndexDuplicateds = other.allowIndexDuplicateds;
216
        this.hidden = other.hidden;
217
        this.dataProfile = other.dataProfile;
218
        
219
        this.availableValues = other.availableValues;
220
        this.description = other.description;
221
        this.minValue = other.minValue;
222
        this.maxValue = other.maxValue;
223
        this.label = other.label;
224
        this.order = other.order;
225
        this.groupName = other.groupName;
226
        if( other.tags==null ) {
227
            this.tags = null;
228
        } else {
229
            try {
230
                this.tags = (Tags) other.tags.clone();
231
            } catch (Exception ex) {
232
            }
233
        }
234
        this.foreingKey = null;
235
        if( other.foreingKey!=null ) {
236
            try {
237
                this.foreingKey = (DefaultForeingKey) other.foreingKey.clone();
238
            } catch (CloneNotSupportedException ex) {
239
            }
240
        }
241
        if( this.foreingKey!=null ) {
242
            this.foreingKey.setDescriptor(this);
243
        }
244
        
245
        // TODO: ? Habria que clonarlos ?
246
        this.availableValuesMethod = other.availableValuesMethod;
247
        this.calculateMethod = other.calculateMethod;
248
        this.relationType = other.relationType;
249
    }
250
    
251
    public void setFeatureType(FeatureType type) {
252
        // Usada en la persistencia
253
        if( type == null ) {
254
            this.typeRef = null;
255
        } else {
256
            this.typeRef = new WeakReference(type);
257
//            LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set FeatureType [%08x], ref [%08x].", this.hashCode(), type.hashCode(), typeRef.hashCode()));
258
        }
259
    }
260
    
261
    @Override
262
    public String getDataTypeName() {
263
        if (this.getDataType() == null) {
264
            return "(unknow)";
265
        }
266
        return this.getDataType().getName();
267
    }
268

    
269
    @Override
270
    public DefaultFeatureAttributeDescriptor getCopy() {
271
        return new DefaultFeatureAttributeDescriptor(this);
272
    }
273

    
274
    @Override
275
    public Object clone() throws CloneNotSupportedException {
276
        return new DefaultFeatureAttributeDescriptor(this);
277
    }
278
    
279
    @Override
280
    public boolean allowNull() {
281
        return allowNull;
282
    }
283

    
284
    @Override
285
    public DataType getDataType() {
286
        if (featureAttributeGetter != null) {
287
            return featureAttributeGetter.getDataType();
288
        }
289
        return this.dataType;
290
    }
291

    
292
    public FeatureAttributeDescriptor setDataType(int type) {
293
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
294
        return this;
295
    }
296

    
297
    @Override
298
    public DateFormat getDateFormat() {
299
        return this.dateFormat;
300
    }
301

    
302
    @Override
303
    public Object getDefaultValue() {
304
        return this.defaultValue;
305
    }
306

    
307
    @Override
308
    public Evaluator getEvaluator() {
309
        return this.evaluator;
310
    }
311

    
312
    @Override
313
    public int getGeometryType() {
314
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
315
            return Geometry.TYPES.UNKNOWN;
316
        }
317
        return this.geometryType;
318
    }
319

    
320
    @Override
321
    public int getGeometrySubType() {
322
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
323
            return Geometry.SUBTYPES.UNKNOWN;
324
        }
325
        return this.geometrySubType;
326
    }
327

    
328
    @Override
329
    public GeometryType getGeomType() {
330
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
331
            return null;
332
        }
333
        if (this.geomType == null) {
334
            try {
335
                this.geomType
336
                        = GeometryLocator.getGeometryManager().getGeometryType(
337
                                this.geometryType, this.geometrySubType);
338
            } catch (GeometryException e) {
339
                throw new RuntimeException(
340
                        "Error getting geometry type with type = "
341
                        + this.geometryType + ", subtype = "
342
                        + this.geometrySubType, e);
343
            }
344
        }
345
        return this.geomType;
346
    }
347

    
348
    @Override
349
    public int getIndex() {
350
        return this.index;
351
    }
352

    
353
    protected FeatureAttributeDescriptor setIndex(int index) {
354
        this.index = index;
355
        return this;
356
    }
357

    
358
    @Override
359
    public int getMaximumOccurrences() {
360
        return this.maximumOccurrences;
361
    }
362

    
363
    @Override
364
    public int getMinimumOccurrences() {
365
        return this.minimumOccurrences;
366
    }
367

    
368
    @Override
369
    public String getName() {
370
        return this.name;
371
    }
372
    
373
    public FeatureAttributeDescriptor setName(String name) {
374
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
375
        this.name = name;
376
        return this;
377
    }
378
    
379
    @Override
380
    public Class getObjectClass() {
381
        if (getDataType().getType() == DataTypes.OBJECT) {
382
            return objectClass;
383
        }
384
        return getDataType().getDefaultClass();
385
    }
386

    
387
    @Override
388
    public int getPrecision() {
389
        return this.precision;
390
    }
391

    
392
    @Override
393
    public IProjection getSRS() {
394
        return this.SRS;
395
    }
396

    
397
    @Override
398
    public Interval getInterval() {
399
        return this.interval;
400
    }
401

    
402
    public IProjection getSRS(WeakReference storeRef) {
403
        if( this.SRS==null ) {
404
            FeatureStore store = (FeatureStore) storeRef.get();
405
            this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
406
        }
407
        return this.SRS;
408
    }
409

    
410

    
411
    @Override
412
    public int getSize() {
413
        return this.size;
414
    }
415

    
416
    @Override
417
    public boolean isPrimaryKey() {
418
        return this.primaryKey;
419
    }
420

    
421
    @Override
422
    public boolean isReadOnly() {
423
        if (this.readOnly) {
424
            return true;
425
        }
426
        if (this.getEvaluator() != null) {
427
            return true;
428
        }
429
        if (this.featureAttributeEmulator != null) {
430
            return !this.featureAttributeEmulator.allowSetting();
431
        }
432
        return false;
433
    }
434

    
435
    @Override
436
    public Object getAdditionalInfo(String infoName) {
437
        if (this.additionalInfo == null) {
438
            return null;
439
        }
440
        return this.additionalInfo.get(infoName);
441
    }
442

    
443
    @Override
444
    public boolean isAutomatic() {
445
        return this.isAutomatic;
446
    }
447

    
448
    @Override
449
    public boolean equals(Object obj) {
450
        if (this == obj) {
451
            return true;
452
        }
453
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
454
            return false;
455
        }
456
        DefaultFeatureAttributeDescriptor other
457
                = (DefaultFeatureAttributeDescriptor) obj;
458

    
459
        if (this.allowNull != other.allowNull) {
460
            return false;
461
        }
462

    
463
        if (this.index != other.index) {
464
            return false;
465
        }
466

    
467
        if (!Objects.equals(this.name, other.name)) {
468
            return false;
469
        }
470

    
471
        if (this.getDataType() != other.getDataType()) {
472
            return false;
473
        }
474

    
475
        if (this.size != other.size) {
476
            return false;
477
        }
478

    
479
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
480
            return false;
481
        }
482

    
483
        if (this.primaryKey != other.primaryKey) {
484
            return false;
485
        }
486

    
487
        if (this.isAutomatic != other.isAutomatic) {
488
            return false;
489
        }
490

    
491
        if (this.readOnly != other.readOnly) {
492
            return false;
493
        }
494

    
495
        if (this.precision != other.precision) {
496
            return false;
497
        }
498

    
499
        if (this.maximumOccurrences != other.maximumOccurrences) {
500
            return false;
501
        }
502

    
503
        if (this.minimumOccurrences != other.minimumOccurrences) {
504
            return false;
505
        }
506

    
507
        if (this.geometryType != other.geometryType) {
508
            return false;
509
        }
510

    
511
        if (this.geometrySubType != other.geometrySubType) {
512
            return false;
513
        }
514

    
515
        if (!Objects.equals(this.evaluator, other.evaluator)) {
516
            return false;
517
        }
518

    
519
        if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
520
            return false;
521
        }
522

    
523
        if (!Objects.equals(this.SRS, other.SRS)) {
524
            return false;
525
        }
526

    
527
        if (!Objects.equals(this.dateFormat, other.dateFormat)) {
528
            return false;
529
        }
530

    
531
        if (!Objects.equals(this.objectClass, other.objectClass)) {
532
            return false;
533
        }
534

    
535
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
536
            return false;
537
        }
538

    
539
        return true;
540
    }
541

    
542
    @Override
543
    public void loadFromState(PersistentState state)
544
            throws PersistenceException {
545
        allowNull = state.getBoolean("allowNull");
546
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
547
        dataProfile = state.getString("dataProfile");
548
        
549
//        FIXME: dateFormat;
550
        try {
551
            defaultValue = dataType.coerce(state.get("defaultValue"));
552
        } catch (CoercionException ex) {
553
        }
554

    
555
        index = state.getInt("index");
556
        maximumOccurrences = state.getInt("maximumOccurrences");
557
        minimumOccurrences = state.getInt("minimumOccurrences");
558
        size = state.getInt("size");
559
        name = state.getString("name");
560
        try {
561
            String objectClassName = state.getString("objectClass"); 
562
            if( !StringUtils.isBlank(objectClassName) ) { 
563
                objectClass = Class.forName(objectClassName); 
564
            }
565
        } catch (Throwable e) {
566
            LOGGER.warn("Can't restore the objectClass of the FeatureAttributreDescriptor", e);
567
        }
568
        precision = state.getInt("precision");
569
        evaluator = (Evaluator) state.get("evaluator");
570
        primaryKey = state.getBoolean("primaryKey");
571
        readOnly = state.getBoolean("readOnly");
572
        SRS = (IProjection) state.get("SRS");
573
        geometryType = state.getInt("geometryType");
574
        geometrySubType = state.getInt("geometrySubType");
575
        if( geometryType!=Geometry.TYPES.UNKNOWN && 
576
                geometrySubType!=Geometry.SUBTYPES.UNKNOWN ) {
577
            geomType = GeometryUtils.getGeometryType(
578
                    geometryType, 
579
                    geometrySubType
580
            );
581
        }
582
//        additionalInfo = (Map) state.get("aditionalInfo");
583
        isAutomatic = state.getBoolean("isAutomatic");
584
        isTime = state.getBoolean("isTime");
585
        if( state.hasValue("intervalStart") ) {
586
            long intervalStart = state.getLong("interval_start");
587
            long intervalEnd = state.getLong("interval_end");
588
            interval = TimeSupportLocator.getManager().createRelativeInterval(intervalStart, intervalEnd);
589
        } else {
590
            interval = null;
591
        }
592
        featureAttributeEmulator = (FeatureAttributeEmulator) state.get("featureAttributeEmulator");
593
        indexed = state.getBoolean("indexed");
594
        isIndexAscending = state.getBoolean("isIndexAscending");
595
        allowIndexDuplicateds = state.getBoolean("allowIndexDuplicateds");
596

    
597
        Map<String,Object> values = state.getMap("availableValues");
598
        if( values == null || values.isEmpty()  ) {
599
            this.availableValues = null;
600
        } else {
601
            this.availableValues = new DynObjectValueItem[values.size()];
602
            int n = 0;
603
            for (Entry<String, Object> entry : values.entrySet()) {
604
                this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
605
            }
606
        }
607
        
608
        description = state.getString("description");
609
        minValue = state.get("minValue");
610
        maxValue = state.get("maxValue");
611
        label = state.getString("label");
612
        order = state.getInt("order");
613
        hidden = state.getBoolean("hidden");
614
        groupName = state.getString("groupName");
615
        relationType = state.getInt("relationType");
616
        
617
        foreingKey = (DefaultForeingKey) state.get("foreingKey");
618
        if( foreingKey!=null ) {
619
            this.foreingKey.setDescriptor(this);
620
        }
621
        tags = (Tags) state.get("tags");
622
        if( tags == null ) {
623
            this.tags = new DefaultTags();
624
        }
625
    }
626

    
627
    @Override
628
    public void saveToState(PersistentState state) throws PersistenceException {
629
        state.set("allowNull", allowNull);
630
        state.set("dataType", dataType.getType());
631
        state.set("dataProfile", dataProfile);
632
        
633
//        FIXME: dateFormat;
634

    
635
        state.set("defaultValue", Objects.toString(defaultValue, null));
636

    
637
        state.set("index", index);
638
        state.set("maximumOccurrences", maximumOccurrences);
639
        state.set("minimumOccurrences", minimumOccurrences);
640
        state.set("size", size);
641
        state.set("name", name);
642
        state.set("objectClass", objectClass==null? null:objectClass.getName());
643
        state.set("precision", precision);
644
        state.set("evaluator", evaluator);
645
        
646
        state.set("primaryKey", primaryKey);
647
        state.set("readOnly", readOnly);
648
        state.set("SRS", SRS);
649
        GeometryType theGeomType = this.getGeomType();
650
        if( theGeomType==null ) {
651
            state.set("geometryType", Geometry.TYPES.UNKNOWN);
652
            state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
653
        } else {
654
            state.set("geometryType", theGeomType.getType());
655
            state.set("geometrySubType", theGeomType.getSubType());
656
        }
657

    
658
//      FIXME: additionalInfo
659

    
660
        state.set("isAutomatic", isAutomatic);
661
        state.set("isTime", isTime);
662
        if( this.interval==null ) {
663
            state.setNull("interval_start");
664
            state.setNull("interval_end");
665
        } else {
666
            state.set("interval_start", ((RelativeInterval)interval).getStart().toMillis());
667
            state.set("interval_end", ((RelativeInterval)interval).getEnd().toMillis());
668
        }
669
        state.set("SRS", SRS);
670

    
671
//      FIXME: featureAttributeGetter
672

    
673
        if( featureAttributeEmulator instanceof Persistent ) {
674
            state.set("featureAttributeEmulator", featureAttributeEmulator);
675
        } else {
676
            state.setNull("featureAttributeEmulator");
677
        }
678

    
679
        state.set("indexed", indexed);
680
        state.set("isIndexAscending", isIndexAscending);
681
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
682
        
683
        if( this.availableValues==null ) {
684
            state.setNull("availableValues");
685
        } else {
686
            Map<String,Object> values = new LinkedHashMap<>();
687
            for (DynObjectValueItem value : availableValues) {
688
                values.put(value.getLabel(),value.getValue());
689
            }
690
            state.set("availableValues", values);
691
        }
692
        state.set("description", description);
693
        state.set("minValue", minValue);
694
        state.set("maxValue", maxValue);
695
        state.set("label", label);
696
        state.set("order", order);
697
        state.set("hidden", hidden);
698
        state.set("groupName", groupName);
699
        state.set("relationType",relationType);
700
        
701
        state.set("foreingKey" ,this.foreingKey);
702
        state.set("tags" ,this.tags);
703

    
704
    }
705
    
706
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
707

    
708
    public static void registerPersistenceDefinition() {
709
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
710
        
711

    
712
        if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
713
                == null) {
714
            DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
715
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
716
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
717
                        + " persistent definition",
718
                    null,
719
                    null
720
            );
721
            definition.addDynFieldBoolean("allowNull");
722
            definition.addDynFieldInt("dataType");
723
            definition.addDynFieldString("dataProfile");
724
//            definition.addDynFieldString("dateFormat");
725
            definition.addDynFieldString("defaultValue");
726
            definition.addDynFieldInt("index");
727
            definition.addDynFieldInt("maximumOccurrences");
728
            definition.addDynFieldInt("minimumOccurrences");
729
            definition.addDynFieldInt("size");
730
            definition.addDynFieldString("name");
731
            definition.addDynFieldString("objectClass");
732
            definition.addDynFieldInt("precision");
733
            definition.addDynFieldObject("evaluator")
734
                    .setClassOfValue(Evaluator.class);
735
            definition.addDynFieldBoolean("primaryKey");
736
            definition.addDynFieldBoolean("readOnly");
737
            definition.addDynFieldObject("SRS")
738
                    .setClassOfValue(IProjection.class);
739
            definition.addDynFieldInt("geometryType");
740
            definition.addDynFieldInt("geometrySubType");
741
//            definition.addDynFieldMap("additionalInfo");
742
            definition.addDynFieldBoolean("isAutomatic");
743
            definition.addDynFieldBoolean("isTime");
744
            definition.addDynFieldLong("interval_start");
745
            definition.addDynFieldLong("interval_end");
746
            definition.addDynFieldObject("featureAttributeEmulator")
747
                    .setClassOfValue(FeatureAttributeEmulator.class);
748
            definition.addDynFieldBoolean("indexed");
749
            definition.addDynFieldBoolean("isIndexAscending");
750
            definition.addDynFieldBoolean("allowIndexDuplicateds");
751
            definition.addDynFieldMap("availableValues");
752
            definition.addDynFieldString("description");
753
            definition.addDynFieldObject("minValue");
754
            definition.addDynFieldObject("maxValue");
755
            definition.addDynFieldString("label");
756
            definition.addDynFieldInt("order");
757
            definition.addDynFieldBoolean("hidden");
758
            definition.addDynFieldString("groupName");
759
            definition.addDynFieldInt("relationType");
760
            
761
            definition.addDynFieldObject("foreingKey")
762
                    .setClassOfValue(DefaultForeingKey.class);
763
            
764
            definition.addDynFieldObject("tags")
765
                    .setClassOfValue(Tags.class);
766
            
767
        }
768
    }
769

    
770
    
771
    /*
772
     * Start of DynField interface Implementation
773
     *
774
     */
775

    
776
    @Override
777
    public Tags getTags() {
778
        return tags;
779
    }
780

    
781
    @Override
782
    public DynObjectValueItem[] getAvailableValues() {
783
        if( this.availableValues == null ) {
784
            if( this.isForeingKey() && this.foreingKey.isClosedList() ) {
785
                return this.foreingKey.getAvailableValues(null);
786
            }
787
        }
788
        return this.availableValues;
789
    }
790

    
791
    @Override
792
    public String getLabelOfValue(Object value) {
793
        if( this.labelOfValueMap != null ) {
794
            String theLabel = this.labelOfValueMap.get(value);
795
            if( theLabel == null ) {
796
                theLabel = Objects.toString(value, "");
797
            }
798
            return theLabel;
799
        }
800
        DynObjectValueItem[] values = this.getAvailableValues();
801
        if( values == null ) {
802
            return Objects.toString(value, "");
803
        }
804
        Map<Object, String> map = new LinkedHashMap<>();
805
        for (DynObjectValueItem theValue : values) {
806
            map.put(theValue.getValue(), theValue.getLabel());
807
        }
808
        this.labelOfValueMap = map;
809
        String theLabel = this.labelOfValueMap.get(value);
810
        if( theLabel == null ) {
811
            theLabel = Objects.toString(value, "");
812
        }
813
        return theLabel;
814
    }
815
    
816
    @Override
817
    public String getDescription() {
818
        if( this.description == null ) {
819
            return getName();
820
        }
821
        return this.description;
822
    }
823

    
824
    @Override
825
    public Object getMaxValue() {
826
        return this.maxValue;
827
    }
828

    
829
    @Override
830
    public Object getMinValue() {
831
        return this.minValue;
832
    }
833

    
834
    @Override
835
    public int getTheTypeOfAvailableValues() {
836
        return 1;
837
    }
838

    
839
    @Override
840
    public int getType() {
841
        if (featureAttributeGetter != null) {
842
            return featureAttributeGetter.getDataType().getType();
843
        }
844
        return getDataType().getType();
845
    }
846

    
847
    @Override
848
    public boolean isMandatory() {
849
        return !allowNull() || isPrimaryKey();
850
    }
851

    
852
    @Override
853
    public boolean isPersistent() {
854
        return false;
855
    }
856

    
857
    @Override
858
    public DynField setAvailableValues(DynObjectValueItem[] values) {
859
        if ( ArrayUtils.isEmpty(values) ) {
860
            this.availableValues = null;
861
        } else {
862
            this.availableValues = values;
863
        }
864
        return this;
865
    }
866

    
867
    @Override
868
    public DynField setDescription(String description) {
869
        this.description = description;
870
        return this;
871
    }
872

    
873
    @Override
874
    public DynField setMandatory(boolean mandatory) {
875
        throw new UnsupportedOperationException();
876
    }
877

    
878
    @Override
879
    public DynField setMaxValue(Object maxValue) {
880
        try {
881
            this.maxValue = this.coerce(maxValue);
882
        } catch (CoercionException e) {
883
            throw new IllegalArgumentException(e);
884
        }
885
        return this;
886
    }
887

    
888
    @Override
889
    public DynField setMinValue(Object minValue) {
890
        try {
891
            this.maxValue = this.coerce(minValue);
892
        } catch (CoercionException e) {
893
            throw new IllegalArgumentException(e);
894
        }
895
        return this;
896
    }
897

    
898
    @Override
899
    public DynField setPersistent(boolean persistent) {
900
        throw new UnsupportedOperationException();
901
    }
902

    
903
    @Override
904
    public DynField setTheTypeOfAvailableValues(int type) {
905
        throw new UnsupportedOperationException();
906
    }
907

    
908
    @Override
909
    public DynField setType(int type) {
910
        throw new UnsupportedOperationException();
911
    }
912

    
913
    @Override
914
    public DynField setDefaultDynValue(Object defaultValue) {
915
        throw new UnsupportedOperationException();
916
    }
917

    
918
    @Override
919
    public Class getClassOfValue() {
920
        return null;
921
    }
922

    
923
    @Override
924
    public DynField getElementsType() {
925
        return null;
926
    }
927

    
928
    @Override
929
    public DynField setClassOfValue(Class theClass)
930
            throws DynFieldIsNotAContainerException {
931
        throw new UnsupportedOperationException();
932
    }
933

    
934
    @Override
935
    public DynField setElementsType(DynStruct type)
936
            throws DynFieldIsNotAContainerException {
937
        throw new UnsupportedOperationException();
938
    }
939

    
940
    @Override
941
    public DynField setElementsType(int type)
942
            throws DynFieldIsNotAContainerException {
943
        throw new UnsupportedOperationException();
944
    }
945

    
946
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
947
        this.dataProfile = dataProfile;
948
        return this;
949
    }
950

    
951
    @Override
952
    public String getDataProfileName() {
953
        return dataProfile;
954
    }
955

    
956
    @Override
957
    public DataProfile getDataProfile() {
958
        if( StringUtils.isBlank(dataProfile) ) {
959
            return null;
960
        }
961
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
962
        return profile;
963
    }
964
    
965
    @Override
966
    public void validate(Object value) throws DynFieldValidateException {
967

    
968
        if (value == null && !this.allowNull()) {
969
            throw new DynFieldValidateException(value, this, null);
970
        }
971

    
972
        try {
973
            this.dataType.coerce(value);
974
        } catch (CoercionException e) {
975
            throw new DynFieldValidateException(value, this, e);
976
        }
977

    
978
        /*
979
         * Other checks will be needed
980
         */
981
    }
982

    
983
    @Override
984
    public String getSubtype() {
985
        if (featureAttributeGetter != null) {
986
            return featureAttributeGetter.getDataType().getSubtype();
987
        }
988
        return this.dataType.getSubtype();
989
    }
990

    
991
    @Override
992
    public Object coerce(Object value) throws CoercionException {
993
        if ( value == null ) {
994
            return value; // O debe devolver this.defaultValue
995
        }
996
        try {
997
            return this.getDataType().coerce(value);
998
        } catch(Exception ex){
999
            throw new RuntimeException(ex);
1000
        }
1001
    }
1002

    
1003
    @Override
1004
    public DynField setAvailableValues(List values) {
1005
        if (  values == null || values.isEmpty() ) {
1006
            this.availableValues = null;
1007
        } else {
1008
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1009
                new DynObjectValueItem[values.size()]
1010
            );
1011
        }
1012
        return this;
1013
    }
1014

    
1015
    @Override
1016
    public String getGroup() {
1017
        return this.groupName;
1018
    }
1019

    
1020
    @Override
1021
    public int getOder() {
1022
        return this.order;
1023
    }
1024

    
1025
    @Override
1026
    public String getLabel() {
1027
        if( this.label == null ) {
1028
            return this.getName();
1029
        }
1030
        return this.label;
1031
    }
1032
    
1033
    @Override
1034
    public String getLocalizedLabel() {
1035
        if( StringUtils.isBlank(this.label) ) {
1036
            return this.getName();
1037
        }
1038
        I18nManager i18n = ToolsLocator.getI18nManager();
1039
        return i18n.getTranslation(this.label);
1040
    }
1041

    
1042
    @Override
1043
    public DynField setLabel(String label) {
1044
        this.label = label;
1045
        return this;
1046
    }
1047

    
1048
    @Override
1049
    public DynField setShortLabel(String shortLabel) {
1050
        this.shortLabel = shortLabel;
1051
        return this;
1052
    }
1053

    
1054
    @Override
1055
    public String getShortLabel() {
1056
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1057
    }
1058

    
1059
    @Override
1060
    public String getLocalizedShortLabel() {
1061
        if( StringUtils.isBlank(shortLabel) ) {
1062
            return this.getLocalizedLabel();
1063
        }
1064
        I18nManager i18n = ToolsLocator.getI18nManager();
1065
        return i18n.getTranslation(shortLabel);
1066
    }
1067

    
1068
    @Override
1069
    public DynField setGroup(String groupName) {
1070
        this.groupName = groupName;
1071
        return this;
1072
    }
1073

    
1074
    @Override
1075
    public DynField setOrder(int order) {
1076
        this.order = order;
1077
        return this;
1078
    }
1079

    
1080
    @Override
1081
    public DynField setHidden(boolean hidden) {
1082
        this.hidden = hidden;
1083
        return this;
1084
    }
1085

    
1086
    @Override
1087
    public boolean isHidden() {
1088
        return this.hidden;
1089
    }
1090

    
1091
    @Override
1092
    public DynField setReadOnly(boolean readOnly) {
1093
        this.readOnly = readOnly;
1094
        return this;
1095
    }
1096

    
1097
    @Override
1098
    public boolean isContainer() {
1099
        return false;
1100
    }
1101

    
1102
    @Override
1103
    public Class getClassOfItems() {
1104
        return null;
1105
    }
1106

    
1107
    @Override
1108
    public DynField setDefaultFieldValue(Object defaultValue) {
1109
        throw new UnsupportedOperationException();
1110
    }
1111

    
1112
    @Override
1113
    public DynField setClassOfItems(Class theClass) {
1114
        throw new UnsupportedOperationException();
1115
    }
1116

    
1117
    @Override
1118
    public DynField setType(DataType type) {
1119
        throw new UnsupportedOperationException();
1120
    }
1121

    
1122
    @Override
1123
    public DynField setSubtype(String subtype) {
1124
        throw new UnsupportedOperationException();
1125
    }
1126

    
1127
    @Override
1128
    public boolean isTime() {
1129
        return isTime;
1130
    }
1131

    
1132
    @Override
1133
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1134
        return featureAttributeGetter;
1135
    }
1136

    
1137
    @Override
1138
    public void setFeatureAttributeGetter(
1139
            FeatureAttributeGetter featureAttributeTransform) {
1140
        this.featureAttributeGetter = featureAttributeTransform;
1141
    }
1142

    
1143
    @Override
1144
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1145
        return this.featureAttributeEmulator;
1146
    }
1147

    
1148
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1149
        this.featureAttributeEmulator = featureAttributeEmulator;
1150
        return this;
1151
    }
1152
        
1153
    @Override
1154
    public boolean isIndexed() {
1155
        return this.indexed;
1156
    }
1157
    
1158
    public boolean isForeingKey() {
1159
        return this.foreingKey!=null && this.foreingKey.isForeingKey();
1160
    }
1161
    
1162
    public ForeingKey getForeingKey() {
1163
        return this.foreingKey;
1164
    }
1165

    
1166
    @Override
1167
    public boolean allowIndexDuplicateds() {
1168
        return this.allowIndexDuplicateds;
1169
    }
1170

    
1171
    @Override
1172
    public boolean isIndexAscending() {
1173
        return this.isIndexAscending;
1174
    }
1175

    
1176
    @Override
1177
    public DynField setClassOfValue(DynStruct dynStrct) {
1178
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1179
    }
1180

    
1181
    @Override
1182
    public DynField setClassOfValue(String theClassNameOfValue) {
1183
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1184
    }
1185

    
1186
    @Override
1187
    public String getClassNameOfValue() {
1188
        return null;
1189
    }
1190

    
1191
    @Override
1192
    public DynStruct getDynClassOfValue() {
1193
        return null;
1194
    }
1195

    
1196
    @Override
1197
    public DynField setTypeOfItems(int type) {
1198
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1199
    }
1200

    
1201
    @Override
1202
    public int getTypeOfItems() {
1203
        return DataTypes.INVALID;
1204
    }
1205

    
1206
    @Override
1207
    public DynField setClassOfItems(DynStruct dynStrct) {
1208
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1209
    }
1210

    
1211
    @Override
1212
    public DynField setClassOfItems(String theClassNameOfValue) {
1213
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1214
    }
1215

    
1216
    @Override
1217
    public String getClassNameOfItems() {
1218
        return null;
1219
    }
1220

    
1221
    @Override
1222
    public DynStruct getDynClassOfItems() {
1223
        return null;
1224
    }
1225

    
1226
    @Override
1227
    public DynField setRelationType(int relationType) {
1228
        this.relationType = relationType;
1229
        return this;
1230
    }
1231

    
1232
    @Override
1233
    public int getRelationType() {
1234
        return this.relationType;
1235
    }
1236

    
1237
    @Override
1238
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1239
        this.availableValuesMethod = availableValuesMethod;
1240
        return this;
1241
    }
1242

    
1243
    @Override
1244
    public DynObjectValueItem[] getAvailableValues(DynObject self) {
1245
        if( this.availableValuesMethod != null ) {
1246
            DynObjectValueItem[] values;
1247
            try {
1248
                values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self,new Object[] {this});
1249
            } catch (DynMethodException ex) {
1250
                return this.availableValues;
1251
            }
1252
            if( values != null ) {
1253
                return values;
1254
            }
1255
        }
1256
        return this.availableValues;
1257
    }
1258

    
1259
    @Override
1260
    public DynMethod getAvailableValuesMethod() {
1261
        return this.availableValuesMethod;
1262
    }
1263

    
1264
    @Override
1265
    public boolean isAvailableValuesCalculated() {
1266
        return this.availableValuesMethod!=null;
1267
    }
1268

    
1269
    @Override
1270
    public DynMethod getCalculateMethod() {
1271
        return this.calculateMethod;
1272
    }
1273

    
1274
    @Override
1275
    public DynField setCalculateMethod(DynMethod method) {
1276
        this.calculateMethod = method;
1277
        return this;
1278
    }
1279
    
1280
    @Override
1281
    public boolean isCalculated() {
1282
        return this.calculateMethod != null;
1283
    }
1284
    
1285
    @Override
1286
    public Object getCalculatedValue(DynObject self) {
1287
        try {
1288
            return this.calculateMethod.invoke(self, new Object[] { this });
1289
        } catch (DynMethodException ex) {
1290
            throw new RuntimeException(ex);
1291
        }
1292
    }
1293

    
1294
    @Override
1295
    public DynField setValidateElements(boolean validate) {
1296
        return this;
1297
    }
1298

    
1299
    @Override
1300
    public boolean getValidateElements() {
1301
        return false;
1302
    }
1303

    
1304
    private class ConstantValueEvaluator extends AbstractEvaluator {
1305

    
1306
        @Override
1307
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1308
            return defaultValue;
1309
        }
1310

    
1311
        @Override
1312
        public String getName() {
1313
            return "Constant attribute " + name;
1314
        }
1315
    }
1316

    
1317
    public void setConstantValue(boolean isConstantValue) {
1318
        if (isConstantValue) {
1319
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1320
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1321
             * el evaluador el que se encarga de proporcionar su valor.
1322
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1323
             * por defecto para ese attributo.
1324
             */
1325
            this.evaluator = new ConstantValueEvaluator();
1326
        } else {
1327
            this.evaluator = null;
1328
        }
1329
    }
1330

    
1331
    @Override
1332
    public boolean isComputed() {
1333
        return featureAttributeEmulator!=null || evaluator!=null || isCalculated();
1334
    }
1335

    
1336
    @Override
1337
    public FeatureStore getStore() {
1338
        FeatureType ftype = this.getFeatureType();
1339
        if( ftype == null ) {
1340
            return null;
1341
        }
1342
        return ftype.getStore();
1343
    }
1344
    
1345
    @Override
1346
    public FeatureType getFeatureType() {
1347
        if( this.typeRef==null ) {
1348
            return null;
1349
        }
1350
        FeatureType ftype = (FeatureType) this.typeRef.get();
1351
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1352
        return ftype;
1353
    }
1354

    
1355
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1356
        this.interval = interval;
1357
        return this;
1358
    }
1359

    
1360
    public void fixAll() {
1361
        switch(this.getType()) {
1362
            case DataTypes.INSTANT:
1363
            case DataTypes.INTERVAL:
1364
            case DataTypes.DATE:
1365
                if( this.getInterval()!=null ) {
1366
                    this.isTime = true;
1367
                }
1368
                break;
1369
        }
1370
    }
1371

    
1372
    @Override
1373
    public String[] getRequiredFieldNames() {
1374
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1375
        if( emulator==null ) {
1376
            return null;
1377
        }
1378
        return emulator.getRequiredFieldNames();
1379
    }
1380

    
1381
    @Override
1382
    public void recentUsed() {
1383
        DefaultFeatureType.RECENTS_USEDS.add(this);
1384
    }
1385

    
1386
}