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

History | View | Annotate | Download (43.1 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
        return this.isComputed();
427
    }
428

    
429
    @Override
430
    public Object getAdditionalInfo(String infoName) {
431
        if (this.additionalInfo == null) {
432
            return null;
433
        }
434
        return this.additionalInfo.get(infoName);
435
    }
436

    
437
    @Override
438
    public boolean isAutomatic() {
439
        return this.isAutomatic;
440
    }
441

    
442
    @Override
443
    public boolean equals(Object obj) {
444
        if (this == obj) {
445
            return true;
446
        }
447
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
448
            return false;
449
        }
450
        DefaultFeatureAttributeDescriptor other
451
                = (DefaultFeatureAttributeDescriptor) obj;
452

    
453
        if (this.allowNull != other.allowNull) {
454
            return false;
455
        }
456

    
457
        if (this.index != other.index) {
458
            return false;
459
        }
460

    
461
        if (!Objects.equals(this.name, other.name)) {
462
            return false;
463
        }
464

    
465
        if (this.getDataType() != other.getDataType()) {
466
            return false;
467
        }
468

    
469
        if (this.size != other.size) {
470
            return false;
471
        }
472

    
473
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
474
            return false;
475
        }
476

    
477
        if (this.primaryKey != other.primaryKey) {
478
            return false;
479
        }
480

    
481
        if (this.isAutomatic != other.isAutomatic) {
482
            return false;
483
        }
484

    
485
        if (this.readOnly != other.readOnly) {
486
            return false;
487
        }
488

    
489
        if (this.precision != other.precision) {
490
            return false;
491
        }
492

    
493
        if (this.maximumOccurrences != other.maximumOccurrences) {
494
            return false;
495
        }
496

    
497
        if (this.minimumOccurrences != other.minimumOccurrences) {
498
            return false;
499
        }
500

    
501
        if (this.geometryType != other.geometryType) {
502
            return false;
503
        }
504

    
505
        if (this.geometrySubType != other.geometrySubType) {
506
            return false;
507
        }
508

    
509
        if (!Objects.equals(this.evaluator, other.evaluator)) {
510
            return false;
511
        }
512

    
513
        if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
514
            return false;
515
        }
516

    
517
        if (!Objects.equals(this.SRS, other.SRS)) {
518
            return false;
519
        }
520

    
521
        if (!Objects.equals(this.dateFormat, other.dateFormat)) {
522
            return false;
523
        }
524

    
525
        if (!Objects.equals(this.objectClass, other.objectClass)) {
526
            return false;
527
        }
528

    
529
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
530
            return false;
531
        }
532

    
533
        return true;
534
    }
535

    
536
    @Override
537
    public void loadFromState(PersistentState state)
538
            throws PersistenceException {
539
        allowNull = state.getBoolean("allowNull");
540
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
541
        dataProfile = state.getString("dataProfile");
542
        
543
//        FIXME: dateFormat;
544
        try {
545
            defaultValue = dataType.coerce(state.get("defaultValue"));
546
        } catch (CoercionException ex) {
547
        }
548

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

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

    
621
    @Override
622
    public void saveToState(PersistentState state) throws PersistenceException {
623
        state.set("allowNull", allowNull);
624
        state.set("dataType", dataType.getType());
625
        state.set("dataProfile", dataProfile);
626
        
627
//        FIXME: dateFormat;
628

    
629
        state.set("defaultValue", Objects.toString(defaultValue, null));
630

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

    
652
//      FIXME: additionalInfo
653

    
654
        state.set("isAutomatic", isAutomatic);
655
        state.set("isTime", isTime);
656
        if( this.interval==null ) {
657
            state.setNull("interval_start");
658
            state.setNull("interval_end");
659
        } else {
660
            state.set("interval_start", ((RelativeInterval)interval).getStart().toMillis());
661
            state.set("interval_end", ((RelativeInterval)interval).getEnd().toMillis());
662
        }
663
        state.set("SRS", SRS);
664

    
665
//      FIXME: featureAttributeGetter
666

    
667
        if( featureAttributeEmulator instanceof Persistent ) {
668
            state.set("featureAttributeEmulator", featureAttributeEmulator);
669
        } else {
670
            state.setNull("featureAttributeEmulator");
671
        }
672

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

    
698
    }
699
    
700
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
701

    
702
    public static void registerPersistenceDefinition() {
703
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
704
        
705

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

    
764
    
765
    /*
766
     * Start of DynField interface Implementation
767
     *
768
     */
769

    
770
    @Override
771
    public Tags getTags() {
772
        return tags;
773
    }
774

    
775
    @Override
776
    public DynObjectValueItem[] getAvailableValues() {
777
        if( this.availableValues == null ) {
778
            if( this.isForeingKey() && this.foreingKey.isClosedList() ) {
779
                return this.foreingKey.getAvailableValues(null);
780
            }
781
        }
782
        return this.availableValues;
783
    }
784

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

    
818
    @Override
819
    public Object getMaxValue() {
820
        return this.maxValue;
821
    }
822

    
823
    @Override
824
    public Object getMinValue() {
825
        return this.minValue;
826
    }
827

    
828
    @Override
829
    public int getTheTypeOfAvailableValues() {
830
        return 1;
831
    }
832

    
833
    @Override
834
    public int getType() {
835
        if (featureAttributeGetter != null) {
836
            return featureAttributeGetter.getDataType().getType();
837
        }
838
        return getDataType().getType();
839
    }
840

    
841
    @Override
842
    public boolean isMandatory() {
843
        return !allowNull() || isPrimaryKey();
844
    }
845

    
846
    @Override
847
    public boolean isPersistent() {
848
        return false;
849
    }
850

    
851
    @Override
852
    public DynField setAvailableValues(DynObjectValueItem[] values) {
853
        if ( ArrayUtils.isEmpty(values) ) {
854
            this.availableValues = null;
855
        } else {
856
            this.availableValues = values;
857
        }
858
        return this;
859
    }
860

    
861
    @Override
862
    public DynField setDescription(String description) {
863
        this.description = description;
864
        return this;
865
    }
866

    
867
    @Override
868
    public DynField setMandatory(boolean mandatory) {
869
        throw new UnsupportedOperationException();
870
    }
871

    
872
    @Override
873
    public DynField setMaxValue(Object maxValue) {
874
        try {
875
            this.maxValue = this.coerce(maxValue);
876
        } catch (CoercionException e) {
877
            throw new IllegalArgumentException(e);
878
        }
879
        return this;
880
    }
881

    
882
    @Override
883
    public DynField setMinValue(Object minValue) {
884
        try {
885
            this.maxValue = this.coerce(minValue);
886
        } catch (CoercionException e) {
887
            throw new IllegalArgumentException(e);
888
        }
889
        return this;
890
    }
891

    
892
    @Override
893
    public DynField setPersistent(boolean persistent) {
894
        throw new UnsupportedOperationException();
895
    }
896

    
897
    @Override
898
    public DynField setTheTypeOfAvailableValues(int type) {
899
        throw new UnsupportedOperationException();
900
    }
901

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

    
907
    @Override
908
    public DynField setDefaultDynValue(Object defaultValue) {
909
        throw new UnsupportedOperationException();
910
    }
911

    
912
    @Override
913
    public Class getClassOfValue() {
914
        return null;
915
    }
916

    
917
    @Override
918
    public DynField getElementsType() {
919
        return null;
920
    }
921

    
922
    @Override
923
    public DynField setClassOfValue(Class theClass)
924
            throws DynFieldIsNotAContainerException {
925
        throw new UnsupportedOperationException();
926
    }
927

    
928
    @Override
929
    public DynField setElementsType(DynStruct type)
930
            throws DynFieldIsNotAContainerException {
931
        throw new UnsupportedOperationException();
932
    }
933

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

    
940
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
941
        this.dataProfile = dataProfile;
942
        return this;
943
    }
944

    
945
    @Override
946
    public String getDataProfileName() {
947
        return dataProfile;
948
    }
949

    
950
    @Override
951
    public DataProfile getDataProfile() {
952
        if( StringUtils.isBlank(dataProfile) ) {
953
            return null;
954
        }
955
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
956
        return profile;
957
    }
958
    
959
    @Override
960
    public void validate(Object value) throws DynFieldValidateException {
961

    
962
        if (value == null && !this.allowNull()) {
963
            throw new DynFieldValidateException(value, this, null);
964
        }
965

    
966
        try {
967
            this.dataType.coerce(value);
968
        } catch (CoercionException e) {
969
            throw new DynFieldValidateException(value, this, e);
970
        }
971

    
972
        /*
973
         * Other checks will be needed
974
         */
975
    }
976

    
977
    @Override
978
    public String getSubtype() {
979
        if (featureAttributeGetter != null) {
980
            return featureAttributeGetter.getDataType().getSubtype();
981
        }
982
        return this.dataType.getSubtype();
983
    }
984

    
985
    @Override
986
    public Object coerce(Object value) throws CoercionException {
987
        if ( value == null ) {
988
            return value; // O debe devolver this.defaultValue
989
        }
990
        try {
991
            return this.getDataType().coerce(value);
992
        } catch(Exception ex){
993
            throw new RuntimeException(ex);
994
        }
995
    }
996

    
997
    @Override
998
    public DynField setAvailableValues(List values) {
999
        if (  values == null || values.isEmpty() ) {
1000
            this.availableValues = null;
1001
        } else {
1002
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1003
                new DynObjectValueItem[values.size()]
1004
            );
1005
        }
1006
        return this;
1007
    }
1008

    
1009
    @Override
1010
    public String getGroup() {
1011
        return this.groupName;
1012
    }
1013

    
1014
    @Override
1015
    public int getOder() {
1016
        return this.order;
1017
    }
1018

    
1019
    @Override
1020
    public String getLabel() {
1021
        if( this.label == null ) {
1022
            return this.getName();
1023
        }
1024
        return this.label;
1025
    }
1026
    
1027
    @Override
1028
    public String getLocalizedLabel() {
1029
        if( StringUtils.isBlank(this.label) ) {
1030
            return this.getName();
1031
        }
1032
        I18nManager i18n = ToolsLocator.getI18nManager();
1033
        return i18n.getTranslation(this.label);
1034
    }
1035

    
1036
    @Override
1037
    public DynField setLabel(String label) {
1038
        this.label = label;
1039
        return this;
1040
    }
1041

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

    
1048
    @Override
1049
    public String getShortLabel() {
1050
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1051
    }
1052

    
1053
    @Override
1054
    public String getLocalizedShortLabel() {
1055
        if( StringUtils.isBlank(shortLabel) ) {
1056
            return this.getLocalizedLabel();
1057
        }
1058
        I18nManager i18n = ToolsLocator.getI18nManager();
1059
        return i18n.getTranslation(shortLabel);
1060
    }
1061

    
1062
    @Override
1063
    public DynField setGroup(String groupName) {
1064
        this.groupName = groupName;
1065
        return this;
1066
    }
1067

    
1068
    @Override
1069
    public DynField setOrder(int order) {
1070
        this.order = order;
1071
        return this;
1072
    }
1073

    
1074
    @Override
1075
    public DynField setHidden(boolean hidden) {
1076
        this.hidden = hidden;
1077
        return this;
1078
    }
1079

    
1080
    @Override
1081
    public boolean isHidden() {
1082
        return this.hidden;
1083
    }
1084

    
1085
    @Override
1086
    public DynField setReadOnly(boolean readOnly) {
1087
        this.readOnly = readOnly;
1088
        return this;
1089
    }
1090

    
1091
    @Override
1092
    public boolean isContainer() {
1093
        return false;
1094
    }
1095

    
1096
    @Override
1097
    public Class getClassOfItems() {
1098
        return null;
1099
    }
1100

    
1101
    @Override
1102
    public DynField setDefaultFieldValue(Object defaultValue) {
1103
        throw new UnsupportedOperationException();
1104
    }
1105

    
1106
    @Override
1107
    public DynField setClassOfItems(Class theClass) {
1108
        throw new UnsupportedOperationException();
1109
    }
1110

    
1111
    @Override
1112
    public DynField setType(DataType type) {
1113
        throw new UnsupportedOperationException();
1114
    }
1115

    
1116
    @Override
1117
    public DynField setSubtype(String subtype) {
1118
        throw new UnsupportedOperationException();
1119
    }
1120

    
1121
    @Override
1122
    public boolean isTime() {
1123
        return isTime;
1124
    }
1125

    
1126
    @Override
1127
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1128
        return featureAttributeGetter;
1129
    }
1130

    
1131
    @Override
1132
    public void setFeatureAttributeGetter(
1133
            FeatureAttributeGetter featureAttributeTransform) {
1134
        this.featureAttributeGetter = featureAttributeTransform;
1135
    }
1136

    
1137
    @Override
1138
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1139
        return this.featureAttributeEmulator;
1140
    }
1141

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

    
1162
    @Override
1163
    public boolean allowIndexDuplicateds() {
1164
        return this.allowIndexDuplicateds;
1165
    }
1166

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

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

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

    
1182
    @Override
1183
    public String getClassNameOfValue() {
1184
        return null;
1185
    }
1186

    
1187
    @Override
1188
    public DynStruct getDynClassOfValue() {
1189
        return null;
1190
    }
1191

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

    
1197
    @Override
1198
    public int getTypeOfItems() {
1199
        return DataTypes.INVALID;
1200
    }
1201

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

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

    
1212
    @Override
1213
    public String getClassNameOfItems() {
1214
        return null;
1215
    }
1216

    
1217
    @Override
1218
    public DynStruct getDynClassOfItems() {
1219
        return null;
1220
    }
1221

    
1222
    @Override
1223
    public DynField setRelationType(int relationType) {
1224
        this.relationType = relationType;
1225
        return this;
1226
    }
1227

    
1228
    @Override
1229
    public int getRelationType() {
1230
        return this.relationType;
1231
    }
1232

    
1233
    @Override
1234
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1235
        this.availableValuesMethod = availableValuesMethod;
1236
        return this;
1237
    }
1238

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

    
1255
    @Override
1256
    public DynMethod getAvailableValuesMethod() {
1257
        return this.availableValuesMethod;
1258
    }
1259

    
1260
    @Override
1261
    public boolean isAvailableValuesCalculated() {
1262
        return this.availableValuesMethod!=null;
1263
    }
1264

    
1265
    @Override
1266
    public DynMethod getCalculateMethod() {
1267
        return this.calculateMethod;
1268
    }
1269

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

    
1290
    @Override
1291
    public DynField setValidateElements(boolean validate) {
1292
        return this;
1293
    }
1294

    
1295
    @Override
1296
    public boolean getValidateElements() {
1297
        return false;
1298
    }
1299

    
1300
    @Override
1301
    public boolean hasLabel() {
1302
        return StringUtils.isNotBlank(this.label);
1303
    }
1304

    
1305
    @Override
1306
    public boolean hasShortLabel() {
1307
        return StringUtils.isNotBlank(this.shortLabel);
1308
    }
1309

    
1310
    @Override
1311
    public boolean hasDescription() {
1312
        return StringUtils.isNotBlank(this.description);
1313
    }
1314

    
1315
    @Override
1316
    public FeatureAttributeDescriptor getValue() {
1317
        return this;
1318
    }
1319

    
1320
    private class ConstantValueEvaluator extends AbstractEvaluator {
1321

    
1322
        @Override
1323
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1324
            return defaultValue;
1325
        }
1326

    
1327
        @Override
1328
        public String getName() {
1329
            return "Constant attribute " + name;
1330
        }
1331
    }
1332

    
1333
    public void setConstantValue(boolean isConstantValue) {
1334
        if (isConstantValue) {
1335
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1336
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1337
             * el evaluador el que se encarga de proporcionar su valor.
1338
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1339
             * por defecto para ese attributo.
1340
             */
1341
            this.evaluator = new ConstantValueEvaluator();
1342
        } else {
1343
            this.evaluator = null;
1344
        }
1345
    }
1346

    
1347
    @Override
1348
    public boolean isComputed() {
1349
        return featureAttributeEmulator!=null || evaluator!=null || isCalculated();
1350
    }
1351

    
1352
    @Override
1353
    public FeatureStore getStore() {
1354
        FeatureType ftype = this.getFeatureType();
1355
        if( ftype == null ) {
1356
            return null;
1357
        }
1358
        return ftype.getStore();
1359
    }
1360
    
1361
    @Override
1362
    public FeatureType getFeatureType() {
1363
        if( this.typeRef==null ) {
1364
            return null;
1365
        }
1366
        FeatureType ftype = (FeatureType) this.typeRef.get();
1367
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1368
        return ftype;
1369
    }
1370

    
1371
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1372
        this.interval = interval;
1373
        return this;
1374
    }
1375

    
1376
    public void fixAll() {
1377
        switch(this.getType()) {
1378
            case DataTypes.INSTANT:
1379
            case DataTypes.INTERVAL:
1380
            case DataTypes.DATE:
1381
                if( this.getInterval()!=null ) {
1382
                    this.isTime = true;
1383
                }
1384
                break;
1385
        }
1386
    }
1387

    
1388
    @Override
1389
    public String[] getRequiredFieldNames() {
1390
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1391
        if( emulator==null ) {
1392
            return null;
1393
        }
1394
        return emulator.getRequiredFieldNames();
1395
    }
1396

    
1397
    @Override
1398
    public void recentUsed() {
1399
        DefaultFeatureType.RECENTS_USEDS.add(this);
1400
    }
1401

    
1402
    @Override
1403
    public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1404
        if( other == null ) {
1405
            throw new NullPointerException();
1406
        }
1407
        DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1408
        if( !StringUtils.equalsIgnoreCase(old.name, this.name) ) {
1409
            return false;
1410
        }
1411
        if( old.isComputed() && old.isComputed()==this.isComputed() ) {
1412
            return true;
1413
        }
1414
        if( this.dataType!=old.dataType ) {
1415
            return false;
1416
        }
1417
        if( this.size != old.size ) {
1418
            return false;
1419
        }
1420
        if( this.precision != old.precision ) {
1421
            return false;
1422
        }
1423
//        if( this.primaryKey != old.primaryKey ) {
1424
//            return false;
1425
//        }
1426
        if( this.geomType != old.geomType ) {
1427
            return false;
1428
        }
1429
        if( this.SRS != old.SRS ) {
1430
            return false;
1431
        }
1432
        if( this.isAutomatic != old.isAutomatic ) {
1433
            return false;
1434
        }
1435
        return true;
1436
    }
1437
    
1438
}