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

History | View | Annotate | Download (50.7 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.math.BigDecimal;
27
import java.math.MathContext;
28
import java.math.RoundingMode;
29
import java.text.DateFormat;
30
import java.util.HashMap;
31
import java.util.Iterator;
32
import java.util.LinkedHashMap;
33
import java.util.List;
34
import java.util.Locale;
35
import java.util.Map;
36
import java.util.Map.Entry;
37
import java.util.Objects;
38
import org.apache.commons.lang3.ArrayUtils;
39
import org.apache.commons.lang3.StringUtils;
40
import org.cresques.cts.IProjection;
41
import org.gvsig.expressionevaluator.ExpressionUtils;
42
import org.gvsig.fmap.dal.DALLocator;
43
import org.gvsig.fmap.dal.DataStore;
44
import org.gvsig.fmap.dal.DataTypes;
45
import org.gvsig.fmap.dal.feature.DataProfile;
46
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
47
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
48
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
49
import org.gvsig.fmap.dal.feature.FeatureStore;
50
import org.gvsig.fmap.dal.feature.FeatureType;
51
import org.gvsig.fmap.dal.feature.ForeingKey;
52
import org.gvsig.fmap.geom.Geometry;
53
import org.gvsig.fmap.geom.GeometryException;
54
import org.gvsig.fmap.geom.GeometryLocator;
55
import org.gvsig.fmap.geom.GeometryUtils;
56
import org.gvsig.fmap.geom.type.GeometryType;
57
import org.gvsig.timesupport.Interval;
58
import org.gvsig.timesupport.RelativeInterval;
59
import org.gvsig.timesupport.TimeSupportLocator;
60
import org.gvsig.tools.ToolsLocator;
61
import org.gvsig.tools.dataTypes.Coercion;
62
import org.gvsig.tools.dataTypes.CoercionException;
63
import org.gvsig.tools.dataTypes.DataType;
64
import org.gvsig.tools.dataTypes.DataTypeUtils;
65
import org.gvsig.tools.dynobject.DynField;
66
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
67
import org.gvsig.tools.dynobject.DynField_v2;
68
import org.gvsig.tools.dynobject.DynMethod;
69
import org.gvsig.tools.dynobject.DynObject;
70
import org.gvsig.tools.dynobject.DynObjectValueItem;
71
import org.gvsig.tools.dynobject.DynStruct;
72
import org.gvsig.tools.dynobject.Tags;
73
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
74
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
75
import org.gvsig.tools.dynobject.exception.DynMethodException;
76
import org.gvsig.tools.dynobject.impl.DefaultTags;
77
import org.gvsig.tools.evaluator.AbstractEvaluator;
78
import org.gvsig.tools.evaluator.Evaluator;
79
import org.gvsig.tools.evaluator.EvaluatorData;
80
import org.gvsig.tools.evaluator.EvaluatorException;
81
import org.gvsig.tools.i18n.I18nManager;
82
import org.gvsig.tools.persistence.PersistenceManager;
83
import org.gvsig.tools.persistence.Persistent;
84
import org.gvsig.tools.persistence.PersistentState;
85
import org.gvsig.tools.persistence.exception.PersistenceException;
86
import org.slf4j.Logger;
87
import org.slf4j.LoggerFactory;
88
import org.gvsig.tools.dataTypes.CoercionContext;
89

    
90
@SuppressWarnings("UseSpecificCatch")
91
public class DefaultFeatureAttributeDescriptor implements
92
        FeatureAttributeDescriptor, Persistent, DynField_v2, DynField_LabelAttribute {
93

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

    
127
    protected DynObjectValueItem[] availableValues;
128
    private Map<Object,String> labelOfValueMap; // No persistente
129
    protected String description;
130
    protected Object minValue;
131
    protected Object maxValue;
132
    protected String label;
133
    protected String shortLabel;
134
    protected int order;
135
    protected boolean hidden;
136
    protected String groupName;
137
    protected Tags tags = new DefaultTags();
138
    private DynMethod availableValuesMethod;
139
    private DynMethod calculateMethod;
140
    private WeakReference typeRef;
141
    protected DefaultForeingKey foreingKey = null;
142
    
143
    protected CoercionContext coerceContext = null; // not persistent
144
    protected MathContext mathContext = null; // not persistent
145
    
146
    private int relationType = RELATION_TYPE_NONE;
147
    protected Locale locale;
148

    
149
    public DefaultFeatureAttributeDescriptor() {
150
        // Usada en la persistencia
151
    }
152

    
153
    protected DefaultFeatureAttributeDescriptor(FeatureType type) {
154
        this();
155
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x].", this.hashCode()));
156
        setFeatureType(type);
157
        this.allowNull = true;
158
        this.dataType = null;
159
        this.dateFormat = null;
160
        this.defaultValue = null;
161
        this.index = -1;
162
        this.maximumOccurrences = 0;
163
        this.minimumOccurrences = 0;
164
        this.size = 0;
165
        this.name = null;
166
        this.objectClass = null;
167
        this.precision = 0;
168
        this.scale = 0;
169
        this.roundMode = BigDecimal.ROUND_HALF_UP;
170
        this.evaluator = null;
171
        this.primaryKey = false;
172
        this.readOnly = false;
173
        this.SRS = null;
174
        this.geometryType = Geometry.TYPES.NULL;
175
        this.geometrySubType = Geometry.SUBTYPES.UNKNOWN;
176
        this.additionalInfo = null;
177
        this.isAutomatic = false;
178
        this.hidden = false;
179
        this.relationType = RELATION_TYPE_NONE;
180
        this.locale = Locale.ENGLISH;
181
    }
182

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

    
289
    @Override
290
    public DefaultFeatureAttributeDescriptor getCopy() {
291
        return new DefaultFeatureAttributeDescriptor(this);
292
    }
293

    
294
    @Override
295
    public Object clone() throws CloneNotSupportedException {
296
        return new DefaultFeatureAttributeDescriptor(this);
297
    }
298
    
299
    @Override
300
    public boolean allowNull() {
301
        return allowNull;
302
    }
303

    
304
    public Locale getLocale() {
305
      return this.locale;
306
    }
307
    
308
    @Override
309
    public DataType getDataType() {
310
        if (featureAttributeGetter != null) {
311
            return featureAttributeGetter.getDataType();
312
        }
313
        return this.dataType;
314
    }
315

    
316
    public FeatureAttributeDescriptor setDataType(int type) {
317
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
318
        return this;
319
    }
320

    
321
    @Override
322
    public DateFormat getDateFormat() {
323
        return this.dateFormat;
324
    }
325

    
326
    @Override
327
    public Object getDefaultValue() {
328
        return this.defaultValue;
329
    }
330

    
331
    @Override
332
    public Object getDefaultValueCoerced() {        
333
        try {
334
            Object value = this.defaultValue;
335
            if( value == null ) {
336
                return null;
337
            }
338
            if( ExpressionUtils.isDynamicText(value.toString()) ) {
339
                value = ExpressionUtils.evaluateDynamicText(value.toString());
340
            }
341
            return this.getDataType().coerce(value);
342
        } catch (CoercionException ex) {
343
            return null;
344
        }
345
    }
346

    
347
    @Override
348
    public Evaluator getEvaluator() {
349
        return this.evaluator;
350
    }
351

    
352
    @Override
353
    public int getGeometryType() {
354
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
355
            return Geometry.TYPES.UNKNOWN;
356
        }
357
        return this.geometryType;
358
    }
359

    
360
    @Override
361
    public int getGeometrySubType() {
362
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
363
            return Geometry.SUBTYPES.UNKNOWN;
364
        }
365
        return this.geometrySubType;
366
    }
367

    
368
    @Override
369
    public GeometryType getGeomType() {
370
        if( this.dataType.getType()!=DataTypes.GEOMETRY ) {
371
            return null;
372
        }
373
        if (this.geomType == null) {
374
            try {
375
                this.geomType
376
                        = GeometryLocator.getGeometryManager().getGeometryType(
377
                                this.geometryType, this.geometrySubType);
378
            } catch (GeometryException e) {
379
                throw new RuntimeException(
380
                        "Error getting geometry type with type = "
381
                        + this.geometryType + ", subtype = "
382
                        + this.geometrySubType, e);
383
            }
384
        }
385
        return this.geomType;
386
    }
387

    
388
    @Override
389
    public int getIndex() {
390
        return this.index;
391
    }
392

    
393
    protected FeatureAttributeDescriptor setIndex(int index) {
394
        this.index = index;
395
        return this;
396
    }
397

    
398
    @Override
399
    public int getMaximumOccurrences() {
400
        return this.maximumOccurrences;
401
    }
402

    
403
    @Override
404
    public int getMinimumOccurrences() {
405
        return this.minimumOccurrences;
406
    }
407

    
408
    @Override
409
    public String getName() {
410
        return this.name;
411
    }
412
    
413
    public FeatureAttributeDescriptor setName(String name) {
414
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
415
        this.name = name;
416
        return this;
417
    }
418
    
419
    @Override
420
    public Class getObjectClass() {
421
        if (getDataType().getType() == DataTypes.OBJECT) {
422
            return objectClass;
423
        }
424
        return getDataType().getDefaultClass();
425
    }
426

    
427
    @Override
428
    public int getPrecision() {
429
        return this.precision;
430
    }
431

    
432
    @Override
433
    public int getScale() {
434
        return this.scale;
435
    }
436

    
437
    @Override
438
    public Coercion getCoercion() {
439
      return this.getDataType().getCoercion();
440
    }
441
    
442
    @Override
443
    public MathContext getMathContext() {
444
      if( this.mathContext==null ) {
445
        if( this.getDataType().isNumeric() ) {
446
          this.mathContext = new MathContext(
447
                  this.getPrecision(), 
448
                  RoundingMode.valueOf(this.getRoundMode())
449
          );
450
        } else {
451
          this.mathContext = MathContext.UNLIMITED;
452
        }
453
      }
454
      return this.mathContext;
455
    }
456
    
457
    @Override
458
    public CoercionContext getCoercionContext() {
459
      if( this.coerceContext==null ) {
460
        if( this.getDataType().isNumeric() ) {
461
          this.coerceContext = DataTypeUtils.coerceContextDecimal(
462
                  this.getLocale(), 
463
                  this.getSize(), 
464
                  this.getPrecision(),
465
                  this.getRoundMode()
466
          );
467
        } else {
468
            this.coerceContext = DataTypeUtils.coerceContextLocale(
469
                    this.getLocale()
470
            );
471
        }
472
      }
473
      return this.coerceContext;
474
    }
475
    
476
    public int getRoundMode() {
477
      return this.roundMode;
478
    }
479
    
480
    @Override
481
    public IProjection getSRS() {
482
        return this.SRS;
483
    }
484

    
485
    @Override
486
    public Interval getInterval() {
487
        return this.interval;
488
    }
489

    
490
    public IProjection getSRS(WeakReference storeRef) {
491
        if( this.SRS==null ) {
492
            FeatureStore store = (FeatureStore) storeRef.get();
493
            this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
494
        }
495
        return this.SRS;
496
    }
497

    
498

    
499
    @Override
500
    public int getSize() {
501
        return this.size;
502
    }
503

    
504
    @Override
505
    public boolean isPrimaryKey() {
506
        return this.primaryKey;
507
    }
508

    
509
    @Override
510
    public boolean isReadOnly() {
511
        if (this.readOnly) {
512
            return true;
513
        }
514
        return this.isComputed();
515
    }
516

    
517
    @Override
518
    public Object getAdditionalInfo(String infoName) {
519
        if (this.additionalInfo == null) {
520
            return null;
521
        }
522
        return this.additionalInfo.get(infoName);
523
    }
524

    
525
    @Override
526
    public boolean isAutomatic() {
527
        return this.isAutomatic;
528
    }
529

    
530
    @Override
531
    public boolean equals(Object obj) {
532
        if (this == obj) {
533
            return true;
534
        }
535
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
536
            return false;
537
        }
538
        DefaultFeatureAttributeDescriptor other
539
                = (DefaultFeatureAttributeDescriptor) obj;
540

    
541
        if (this.allowNull != other.allowNull) {
542
            return false;
543
        }
544

    
545
        if (this.index != other.index) {
546
            return false;
547
        }
548

    
549
        if (!Objects.equals(this.name, other.name)) {
550
            return false;
551
        }
552

    
553
        if (this.getDataType() != other.getDataType()) {
554
            return false;
555
        }
556

    
557
        if (this.size != other.size) {
558
            return false;
559
        }
560

    
561
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
562
            return false;
563
        }
564

    
565
        if (this.primaryKey != other.primaryKey) {
566
            return false;
567
        }
568

    
569
        if (this.isAutomatic != other.isAutomatic) {
570
            return false;
571
        }
572

    
573
        if (this.readOnly != other.readOnly) {
574
            return false;
575
        }
576

    
577
        if (this.precision != other.precision) {
578
            return false;
579
        }
580

    
581
        if (this.maximumOccurrences != other.maximumOccurrences) {
582
            return false;
583
        }
584

    
585
        if (this.minimumOccurrences != other.minimumOccurrences) {
586
            return false;
587
        }
588

    
589
        if (this.geometryType != other.geometryType) {
590
            return false;
591
        }
592

    
593
        if (this.geometrySubType != other.geometrySubType) {
594
            return false;
595
        }
596

    
597
        if (!Objects.equals(this.evaluator, other.evaluator)) {
598
            return false;
599
        }
600

    
601
        if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
602
            return false;
603
        }
604

    
605
        if (!Objects.equals(this.SRS, other.SRS)) {
606
            return false;
607
        }
608

    
609
        if (!Objects.equals(this.dateFormat, other.dateFormat)) {
610
            return false;
611
        }
612

    
613
        if (!Objects.equals(this.objectClass, other.objectClass)) {
614
            return false;
615
        }
616

    
617
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
618
            return false;
619
        }
620

    
621
        return true;
622
    }
623

    
624
    @Override
625
    public void loadFromState(PersistentState state)
626
            throws PersistenceException {
627
        allowNull = state.getBoolean("allowNull");
628
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
629
        dataProfile = state.getString("dataProfile");
630
        
631
//        FIXME: dateFormat;
632
        try {
633
            defaultValue = dataType.coerce(state.get("defaultValue"));
634
        } catch (CoercionException ex) {
635
        }
636

    
637
        index = state.getInt("index");
638
        maximumOccurrences = state.getInt("maximumOccurrences");
639
        minimumOccurrences = state.getInt("minimumOccurrences");
640
        size = state.getInt("size");
641
        name = state.getString("name");
642
        try {
643
            String objectClassName = state.getString("objectClass"); 
644
            if( !StringUtils.isBlank(objectClassName) ) { 
645
                objectClass = Class.forName(objectClassName); 
646
            }
647
        } catch (Throwable e) {
648
            LOGGER.warn("Can't restore the objectClass of the FeatureAttributreDescriptor", e);
649
        }
650
        precision = state.getInt("precision");
651
        scale = state.getInt("scale");
652
        roundMode = state.getInt("roundMode");
653
        String locale_s = state.getString("locale");
654
        locale = StringUtils.isBlank(locale_s)? null:Locale.forLanguageTag(locale_s);
655
        evaluator = (Evaluator) state.get("evaluator");
656
        primaryKey = state.getBoolean("primaryKey");
657
        readOnly = state.getBoolean("readOnly");
658
        SRS = (IProjection) state.get("SRS");
659
        geometryType = state.getInt("geometryType");
660
        geometrySubType = state.getInt("geometrySubType");
661
        if( geometryType!=Geometry.TYPES.UNKNOWN && 
662
                geometrySubType!=Geometry.SUBTYPES.UNKNOWN ) {
663
            geomType = GeometryUtils.getGeometryType(
664
                    geometryType, 
665
                    geometrySubType
666
            );
667
        }
668
//        additionalInfo = (Map) state.get("aditionalInfo");
669
        isAutomatic = state.getBoolean("isAutomatic");
670
        isTime = state.getBoolean("isTime");
671
        if( state.hasValue("intervalStart") ) {
672
            long intervalStart = state.getLong("interval_start");
673
            long intervalEnd = state.getLong("interval_end");
674
            interval = TimeSupportLocator.getManager().createRelativeInterval(intervalStart, intervalEnd);
675
        } else {
676
            interval = null;
677
        }
678
        featureAttributeEmulator = (FeatureAttributeEmulator) state.get("featureAttributeEmulator");
679
        indexed = state.getBoolean("indexed");
680
        isIndexAscending = state.getBoolean("isIndexAscending");
681
        allowIndexDuplicateds = state.getBoolean("allowIndexDuplicateds");
682

    
683
        Map<String,Object> values = state.getMap("availableValues");
684
        if( values == null || values.isEmpty()  ) {
685
            this.availableValues = null;
686
        } else {
687
            this.availableValues = new DynObjectValueItem[values.size()];
688
            int n = 0;
689
            for (Entry<String, Object> entry : values.entrySet()) {
690
                this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
691
            }
692
        }
693
        
694
        description = state.getString("description");
695
        minValue = state.get("minValue");
696
        maxValue = state.get("maxValue");
697
        label = state.getString("label");
698
        order = state.getInt("order");
699
        hidden = state.getBoolean("hidden");
700
        groupName = state.getString("groupName");
701
        relationType = state.getInt("relationType");
702
        
703
        foreingKey = (DefaultForeingKey) state.get("foreingKey");
704
        if( foreingKey!=null ) {
705
            this.foreingKey.setDescriptor(this);
706
        }
707
        tags = (Tags) state.get("tags");
708
        if( tags == null ) {
709
            this.tags = new DefaultTags();
710
        }
711
    }
712

    
713
    @Override
714
    public void saveToState(PersistentState state) throws PersistenceException {
715
        state.set("allowNull", allowNull);
716
        state.set("dataType", dataType.getType());
717
        state.set("dataProfile", dataProfile);
718
        
719
//        FIXME: dateFormat;
720

    
721
        state.set("defaultValue", Objects.toString(defaultValue, null));
722

    
723
        state.set("index", index);
724
        state.set("maximumOccurrences", maximumOccurrences);
725
        state.set("minimumOccurrences", minimumOccurrences);
726
        state.set("size", size);
727
        state.set("name", name);
728
        state.set("objectClass", objectClass==null? null:objectClass.getName());
729
        state.set("precision", precision);
730
        state.set("scale", scale);
731
        state.set("roundMode", roundMode);
732
        state.set("locale", this.locale==null? null:this.locale.toLanguageTag());
733
        state.set("evaluator", evaluator);
734
        
735
        state.set("primaryKey", primaryKey);
736
        state.set("readOnly", readOnly);
737
        state.set("SRS", SRS);
738
        GeometryType theGeomType = this.getGeomType();
739
        if( theGeomType==null ) {
740
            state.set("geometryType", Geometry.TYPES.UNKNOWN);
741
            state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
742
        } else {
743
            state.set("geometryType", theGeomType.getType());
744
            state.set("geometrySubType", theGeomType.getSubType());
745
        }
746

    
747
//      FIXME: additionalInfo
748

    
749
        state.set("isAutomatic", isAutomatic);
750
        state.set("isTime", isTime);
751
        if( this.interval==null ) {
752
            state.setNull("interval_start");
753
            state.setNull("interval_end");
754
        } else {
755
            state.set("interval_start", ((RelativeInterval)interval).getStart().toMillis());
756
            state.set("interval_end", ((RelativeInterval)interval).getEnd().toMillis());
757
        }
758
        state.set("SRS", SRS);
759

    
760
//      FIXME: featureAttributeGetter
761

    
762
        if( featureAttributeEmulator instanceof Persistent ) {
763
            state.set("featureAttributeEmulator", featureAttributeEmulator);
764
        } else {
765
            state.setNull("featureAttributeEmulator");
766
        }
767

    
768
        state.set("indexed", indexed);
769
        state.set("isIndexAscending", isIndexAscending);
770
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
771
        
772
        if( this.availableValues==null ) {
773
            state.setNull("availableValues");
774
        } else {
775
            Map<String,Object> values = new LinkedHashMap<>();
776
            for (DynObjectValueItem value : availableValues) {
777
                values.put(value.getLabel(),value.getValue());
778
            }
779
            state.set("availableValues", values);
780
        }
781
        state.set("description", description);
782
        state.set("minValue", minValue);
783
        state.set("maxValue", maxValue);
784
        state.set("label", label);
785
        state.set("order", order);
786
        state.set("hidden", hidden);
787
        state.set("groupName", groupName);
788
        state.set("relationType",relationType);
789
        
790
        state.set("foreingKey" ,this.foreingKey);
791
        state.set("tags" ,this.tags);
792

    
793
    }
794
    
795
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
796

    
797
    public static void registerPersistenceDefinition() {
798
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
799
        
800

    
801
        if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
802
                == null) {
803
            DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
804
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
805
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
806
                        + " persistent definition",
807
                    null,
808
                    null
809
            );
810
            definition.addDynFieldBoolean("allowNull");
811
            definition.addDynFieldInt("dataType");
812
            definition.addDynFieldString("dataProfile");
813
//            definition.addDynFieldString("dateFormat");
814
            definition.addDynFieldString("defaultValue");
815
            definition.addDynFieldInt("index");
816
            definition.addDynFieldInt("maximumOccurrences");
817
            definition.addDynFieldInt("minimumOccurrences");
818
            definition.addDynFieldInt("size");
819
            definition.addDynFieldString("name");
820
            definition.addDynFieldString("objectClass");
821
            definition.addDynFieldInt("precision");
822
            definition.addDynFieldInt("scale");
823
            definition.addDynFieldInt("roundMode");
824
            definition.addDynFieldString("locale");
825
            definition.addDynFieldObject("evaluator")
826
                    .setClassOfValue(Evaluator.class);
827
            definition.addDynFieldBoolean("primaryKey");
828
            definition.addDynFieldBoolean("readOnly");
829
            definition.addDynFieldObject("SRS")
830
                    .setClassOfValue(IProjection.class);
831
            definition.addDynFieldInt("geometryType");
832
            definition.addDynFieldInt("geometrySubType");
833
//            definition.addDynFieldMap("additionalInfo");
834
            definition.addDynFieldBoolean("isAutomatic");
835
            definition.addDynFieldBoolean("isTime");
836
            definition.addDynFieldLong("interval_start");
837
            definition.addDynFieldLong("interval_end");
838
            definition.addDynFieldObject("featureAttributeEmulator")
839
                    .setClassOfValue(FeatureAttributeEmulator.class);
840
            definition.addDynFieldBoolean("indexed");
841
            definition.addDynFieldBoolean("isIndexAscending");
842
            definition.addDynFieldBoolean("allowIndexDuplicateds");
843
            definition.addDynFieldMap("availableValues")
844
                    .setClassOfItems(Object.class);
845
            definition.addDynFieldString("description");
846
            definition.addDynFieldObject("minValue");
847
            definition.addDynFieldObject("maxValue");
848
            definition.addDynFieldString("label");
849
            definition.addDynFieldInt("order");
850
            definition.addDynFieldBoolean("hidden");
851
            definition.addDynFieldString("groupName");
852
            definition.addDynFieldInt("relationType");
853
            
854
            definition.addDynFieldObject("foreingKey")
855
                    .setClassOfValue(DefaultForeingKey.class);
856
            
857
            definition.addDynFieldObject("tags")
858
                    .setClassOfValue(Tags.class);
859
            
860
        }
861
    }
862

    
863
    
864
    /*
865
     * Start of DynField interface Implementation
866
     *
867
     */
868

    
869
    @Override
870
    public Tags getTags() {
871
        return tags;
872
    }
873

    
874
    @Override
875
    public DynObjectValueItem[] getAvailableValues() {
876
        if( this.availableValues == null ) {
877
            if( this.isForeingKey() && this.foreingKey.isClosedList() ) {
878
                return this.foreingKey.getAvailableValues(null);
879
            }
880
        }
881
        return this.availableValues;
882
    }
883

    
884
    @Override
885
    public String getLabelOfValue(Object value) {
886
        if( this.labelOfValueMap != null ) {
887
            String theLabel = this.labelOfValueMap.get(value);
888
            if( theLabel == null ) {
889
                theLabel = Objects.toString(value, "");
890
            }
891
            return theLabel;
892
        }
893
        DynObjectValueItem[] values = this.getAvailableValues();
894
        if( values == null ) {
895
            return Objects.toString(value, "");
896
        }
897
        Map<Object, String> map = new LinkedHashMap<>();
898
        for (DynObjectValueItem theValue : values) {
899
            map.put(theValue.getValue(), theValue.getLabel());
900
        }
901
        this.labelOfValueMap = map;
902
        String theLabel = this.labelOfValueMap.get(value);
903
        if( theLabel == null ) {
904
            theLabel = Objects.toString(value, "");
905
        }
906
        return theLabel;
907
    }
908
    
909
    @Override
910
    public String getDescription() {
911
        if( this.description == null ) {
912
            return getName();
913
        }
914
        return this.description;
915
    }
916

    
917
    @Override
918
    public Object getMaxValue() {
919
        return this.maxValue;
920
    }
921

    
922
    @Override
923
    public Object getMinValue() {
924
        return this.minValue;
925
    }
926

    
927
    @Override
928
    public int getTheTypeOfAvailableValues() {
929
        return 1;
930
    }
931

    
932
    @Override
933
    public int getType() {
934
        if (featureAttributeGetter != null) {
935
            return featureAttributeGetter.getDataType().getType();
936
        }
937
        return getDataType().getType();
938
    }
939

    
940
    @Override
941
    public boolean isMandatory() {
942
        return !allowNull() || isPrimaryKey();
943
    }
944

    
945
    @Override
946
    public boolean isPersistent() {
947
        return false;
948
    }
949

    
950
    @Override
951
    public DynField setAvailableValues(DynObjectValueItem[] values) {
952
        if ( ArrayUtils.isEmpty(values) ) {
953
            this.availableValues = null;
954
        } else {
955
            this.availableValues = values;
956
        }
957
        return this;
958
    }
959

    
960
    @Override
961
    public DynField setDescription(String description) {
962
        this.description = description;
963
        return this;
964
    }
965

    
966
    @Override
967
    public DynField setMandatory(boolean mandatory) {
968
        throw new UnsupportedOperationException();
969
    }
970

    
971
    @Override
972
    public DynField setMaxValue(Object maxValue) {
973
        try {
974
            this.maxValue = this.coerce(maxValue);
975
        } catch (CoercionException e) {
976
            throw new IllegalArgumentException(e);
977
        }
978
        return this;
979
    }
980

    
981
    @Override
982
    public DynField setMinValue(Object minValue) {
983
        try {
984
            this.maxValue = this.coerce(minValue);
985
        } catch (CoercionException e) {
986
            throw new IllegalArgumentException(e);
987
        }
988
        return this;
989
    }
990

    
991
    @Override
992
    public DynField setPersistent(boolean persistent) {
993
        throw new UnsupportedOperationException();
994
    }
995

    
996
    @Override
997
    public DynField setTheTypeOfAvailableValues(int type) {
998
        throw new UnsupportedOperationException();
999
    }
1000

    
1001
    @Override
1002
    public DynField setType(int type) {
1003
        throw new UnsupportedOperationException();
1004
    }
1005

    
1006
    @Override
1007
    public DynField setDefaultDynValue(Object defaultValue) {
1008
        throw new UnsupportedOperationException();
1009
    }
1010

    
1011
    @Override
1012
    public Class getClassOfValue() {
1013
        return null;
1014
    }
1015

    
1016
    @Override
1017
    public DynField getElementsType() {
1018
        return null;
1019
    }
1020

    
1021
    @Override
1022
    public DynField setClassOfValue(Class theClass)
1023
            throws DynFieldIsNotAContainerException {
1024
        throw new UnsupportedOperationException();
1025
    }
1026

    
1027
    @Override
1028
    public DynField setElementsType(DynStruct type)
1029
            throws DynFieldIsNotAContainerException {
1030
        throw new UnsupportedOperationException();
1031
    }
1032

    
1033
    @Override
1034
    public DynField setElementsType(int type)
1035
            throws DynFieldIsNotAContainerException {
1036
        throw new UnsupportedOperationException();
1037
    }
1038

    
1039
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1040
        this.dataProfile = dataProfile;
1041
        return this;
1042
    }
1043

    
1044
    @Override
1045
    public String getDataProfileName() {
1046
        return dataProfile;
1047
    }
1048

    
1049
    @Override
1050
    public DataProfile getDataProfile() {
1051
        if( StringUtils.isBlank(dataProfile) ) {
1052
            return null;
1053
        }
1054
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1055
        return profile;
1056
    }
1057
    
1058
    @Override
1059
    public void validate(Object value) throws DynFieldValidateException {
1060

    
1061
        if (value == null && !this.allowNull()) {
1062
            throw new DynFieldValidateException(value, this, null);
1063
        }
1064

    
1065
        try {
1066
            this.dataType.coerce(value);
1067
        } catch (CoercionException e) {
1068
            throw new DynFieldValidateException(value, this, e);
1069
        }
1070

    
1071
        /*
1072
         * Other checks will be needed
1073
         */
1074
    }
1075

    
1076
    @Override
1077
    public String getSubtype() {
1078
        if (featureAttributeGetter != null) {
1079
            return featureAttributeGetter.getDataType().getSubtype();
1080
        }
1081
        return this.dataType.getSubtype();
1082
    }
1083

    
1084
    @Override
1085
    public Object coerce(Object value) throws CoercionException {
1086
        if ( value == null ) {
1087
            return value; // O debe devolver this.defaultValue
1088
        }
1089
        try {
1090
            return this.getDataType().coerce(value);
1091
        } catch(Exception ex){
1092
            throw new RuntimeException(ex);
1093
        }
1094
    }
1095

    
1096
    @Override
1097
    public DynField setAvailableValues(List values) {
1098
        if (  values == null || values.isEmpty() ) {
1099
            this.availableValues = null;
1100
        } else {
1101
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1102
                new DynObjectValueItem[values.size()]
1103
            );
1104
        }
1105
        return this;
1106
    }
1107

    
1108
    @Override
1109
    public String getGroup() {
1110
        return this.groupName;
1111
    }
1112

    
1113
    @Override
1114
    public int getOder() {
1115
        return this.order;
1116
    }
1117

    
1118
    @Override
1119
    public String getLabel() {
1120
        if( this.label == null ) {
1121
            return this.getName();
1122
        }
1123
        return this.label;
1124
    }
1125
    
1126
    @Override
1127
    public String getLocalizedLabel() {
1128
        if( StringUtils.isBlank(this.label) ) {
1129
            return this.getName();
1130
        }
1131
        I18nManager i18n = ToolsLocator.getI18nManager();
1132
        return i18n.getTranslation(this.label);
1133
    }
1134

    
1135
    @Override
1136
    public DynField setLabel(String label) {
1137
        this.label = label;
1138
        return this;
1139
    }
1140

    
1141
    @Override
1142
    public DynField setShortLabel(String shortLabel) {
1143
        this.shortLabel = shortLabel;
1144
        return this;
1145
    }
1146

    
1147
    @Override
1148
    public String getShortLabel() {
1149
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1150
    }
1151

    
1152
    @Override
1153
    public String getLocalizedShortLabel() {
1154
        if( StringUtils.isBlank(shortLabel) ) {
1155
            return this.getLocalizedLabel();
1156
        }
1157
        I18nManager i18n = ToolsLocator.getI18nManager();
1158
        return i18n.getTranslation(shortLabel);
1159
    }
1160

    
1161
    @Override
1162
    public DynField setGroup(String groupName) {
1163
        this.groupName = groupName;
1164
        return this;
1165
    }
1166

    
1167
    @Override
1168
    public DynField setOrder(int order) {
1169
        this.order = order;
1170
        return this;
1171
    }
1172

    
1173
    @Override
1174
    public DynField setHidden(boolean hidden) {
1175
        this.hidden = hidden;
1176
        return this;
1177
    }
1178

    
1179
    @Override
1180
    public boolean isHidden() {
1181
        return this.hidden;
1182
    }
1183

    
1184
    @Override
1185
    public DynField setReadOnly(boolean readOnly) {
1186
        this.readOnly = readOnly;
1187
        return this;
1188
    }
1189

    
1190
    @Override
1191
    public boolean isContainer() {
1192
        return false;
1193
    }
1194

    
1195
    @Override
1196
    public Class getClassOfItems() {
1197
        return null;
1198
    }
1199

    
1200
    @Override
1201
    public DynField setDefaultFieldValue(Object defaultValue) {
1202
        throw new UnsupportedOperationException();
1203
    }
1204

    
1205
    @Override
1206
    public DynField setClassOfItems(Class theClass) {
1207
        throw new UnsupportedOperationException();
1208
    }
1209

    
1210
    @Override
1211
    public DynField setType(DataType type) {
1212
        throw new UnsupportedOperationException();
1213
    }
1214

    
1215
    @Override
1216
    public DynField setSubtype(String subtype) {
1217
        throw new UnsupportedOperationException();
1218
    }
1219

    
1220
    @Override
1221
    public boolean isTime() {
1222
        return isTime;
1223
    }
1224

    
1225
    @Override
1226
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1227
        return featureAttributeGetter;
1228
    }
1229

    
1230
    @Override
1231
    public void setFeatureAttributeGetter(
1232
            FeatureAttributeGetter featureAttributeTransform) {
1233
        this.featureAttributeGetter = featureAttributeTransform;
1234
    }
1235

    
1236
    @Override
1237
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1238
        return this.featureAttributeEmulator;
1239
    }
1240

    
1241
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1242
        this.featureAttributeEmulator = featureAttributeEmulator;
1243
        return this;
1244
    }
1245
        
1246
    @Override
1247
    public boolean isIndexed() {
1248
        return this.indexed;
1249
    }
1250
    
1251
    @Override
1252
    public boolean isForeingKey() {
1253
        return this.foreingKey!=null && this.foreingKey.isForeingKey();
1254
    }
1255
    
1256
    @Override
1257
    public ForeingKey getForeingKey() {
1258
        return this.foreingKey;
1259
    }
1260

    
1261
    @Override
1262
    public boolean allowIndexDuplicateds() {
1263
        return this.allowIndexDuplicateds;
1264
    }
1265

    
1266
    @Override
1267
    public boolean isIndexAscending() {
1268
        return this.isIndexAscending;
1269
    }
1270

    
1271
    @Override
1272
    public DynField setClassOfValue(DynStruct dynStrct) {
1273
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1274
    }
1275

    
1276
    @Override
1277
    public DynField setClassOfValue(String theClassNameOfValue) {
1278
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1279
    }
1280

    
1281
    @Override
1282
    public String getClassNameOfValue() {
1283
        return null;
1284
    }
1285

    
1286
    @Override
1287
    public DynStruct getDynClassOfValue() {
1288
        return null;
1289
    }
1290

    
1291
    @Override
1292
    public DynField setTypeOfItems(int type) {
1293
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1294
    }
1295

    
1296
    @Override
1297
    public int getTypeOfItems() {
1298
        return DataTypes.INVALID;
1299
    }
1300

    
1301
    @Override
1302
    public DynField setClassOfItems(DynStruct dynStrct) {
1303
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1304
    }
1305

    
1306
    @Override
1307
    public DynField setClassOfItems(String theClassNameOfValue) {
1308
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1309
    }
1310

    
1311
    @Override
1312
    public String getClassNameOfItems() {
1313
        return null;
1314
    }
1315

    
1316
    @Override
1317
    public DynStruct getDynClassOfItems() {
1318
        return null;
1319
    }
1320

    
1321
    @Override
1322
    public DynField setRelationType(int relationType) {
1323
        this.relationType = relationType;
1324
        return this;
1325
    }
1326

    
1327
    @Override
1328
    public int getRelationType() {
1329
        return this.relationType;
1330
    }
1331

    
1332
    @Override
1333
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1334
        this.availableValuesMethod = availableValuesMethod;
1335
        return this;
1336
    }
1337

    
1338
    @Override
1339
    public DynObjectValueItem[] getAvailableValues(DynObject self) {
1340
        if( this.availableValuesMethod != null ) {
1341
            DynObjectValueItem[] values;
1342
            try {
1343
                values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self,new Object[] {this});
1344
            } catch (DynMethodException ex) {
1345
                return this.availableValues;
1346
            }
1347
            if( values != null ) {
1348
                return values;
1349
            }
1350
        }
1351
        return this.availableValues;
1352
    }
1353

    
1354
    @Override
1355
    public DynMethod getAvailableValuesMethod() {
1356
        return this.availableValuesMethod;
1357
    }
1358

    
1359
    @Override
1360
    public boolean isAvailableValuesCalculated() {
1361
        return this.availableValuesMethod!=null;
1362
    }
1363

    
1364
    @Override
1365
    public DynMethod getCalculateMethod() {
1366
        return this.calculateMethod;
1367
    }
1368

    
1369
    @Override
1370
    public DynField setCalculateMethod(DynMethod method) {
1371
        this.calculateMethod = method;
1372
        return this;
1373
    }
1374
    
1375
    @Override
1376
    public boolean isCalculated() {
1377
        return this.calculateMethod != null;
1378
    }
1379
    
1380
    @Override
1381
    public Object getCalculatedValue(DynObject self) {
1382
        try {
1383
            return this.calculateMethod.invoke(self, new Object[] { this });
1384
        } catch (DynMethodException ex) {
1385
            throw new RuntimeException(ex);
1386
        }
1387
    }
1388

    
1389
    @Override
1390
    public DynField setValidateElements(boolean validate) {
1391
        return this;
1392
    }
1393

    
1394
    @Override
1395
    public boolean getValidateElements() {
1396
        return false;
1397
    }
1398

    
1399
    @Override
1400
    public boolean hasLabel() {
1401
        return StringUtils.isNotBlank(this.label);
1402
    }
1403

    
1404
    @Override
1405
    public boolean hasShortLabel() {
1406
        return StringUtils.isNotBlank(this.shortLabel);
1407
    }
1408

    
1409
    @Override
1410
    public boolean hasDescription() {
1411
        return StringUtils.isNotBlank(this.description);
1412
    }
1413

    
1414
    @Override
1415
    public FeatureAttributeDescriptor getValue() {
1416
        return this;
1417
    }
1418

    
1419
    private class ConstantValueEvaluator extends AbstractEvaluator {
1420

    
1421
        @Override
1422
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1423
            return defaultValue;
1424
        }
1425

    
1426
        @Override
1427
        public String getName() {
1428
            return "Constant attribute " + name;
1429
        }
1430
    }
1431

    
1432
    public void setConstantValue(boolean isConstantValue) {
1433
        if (isConstantValue) {
1434
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1435
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1436
             * el evaluador el que se encarga de proporcionar su valor.
1437
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1438
             * por defecto para ese attributo.
1439
             */
1440
            this.evaluator = new ConstantValueEvaluator();
1441
        } else {
1442
            this.evaluator = null;
1443
        }
1444
    }
1445

    
1446
    @Override
1447
    public boolean isComputed() {
1448
        return featureAttributeEmulator!=null || evaluator!=null || isCalculated();
1449
    }
1450

    
1451
    @Override
1452
    public FeatureStore getStore() {
1453
        FeatureType ftype = this.getFeatureType();
1454
        if( ftype == null ) {
1455
            return null;
1456
        }
1457
        return ftype.getStore();
1458
    }
1459
    
1460
    @Override
1461
    public FeatureType getFeatureType() {
1462
        if( this.typeRef==null ) {
1463
            return null;
1464
        }
1465
        FeatureType ftype = (FeatureType) this.typeRef.get();
1466
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1467
        return ftype;
1468
    }
1469

    
1470
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1471
        this.interval = interval;
1472
        return this;
1473
    }
1474

    
1475
    public void fixAll() {
1476
        switch(this.getType()) {
1477
            case DataTypes.INSTANT:
1478
            case DataTypes.INTERVAL:
1479
            case DataTypes.DATE:
1480
            case DataTypes.TIME:
1481
            case DataTypes.TIMESTAMP:
1482
                if( this.getInterval()!=null ) {
1483
                    this.isTime = true;
1484
                }
1485
                this.size = 0;
1486
                this.precision = 0;
1487
                this.scale = 0;
1488
                break;
1489
            case DataTypes.BOOLEAN:
1490
            case DataTypes.CHAR:
1491
            case DataTypes.CRS:
1492
            case DataTypes.ENVELOPE:
1493
            case DataTypes.GEOMETRY:
1494
            case DataTypes.VERSION:
1495
                this.size = 0;
1496
                this.precision = 0;
1497
                this.scale = 0;
1498
                break;
1499
            case DataTypes.INT:
1500
                this.size = 0;
1501
                this.precision = INT_MAX_PRECISION;
1502
                this.scale = 0;
1503
                break;
1504
            case DataTypes.LONG:
1505
                this.size = 0;
1506
                this.precision = LONG_MAX_PRECISION;
1507
                this.scale = 0;
1508
                break;
1509
            case DataTypes.BYTE:
1510
                this.size = 0;
1511
                this.precision = BYTE_MAX_PRECISION;
1512
                this.scale = 0;
1513
                break;
1514
            case DataTypes.FLOAT:
1515
                this.size = 0;
1516
                this.fixPrecisionAndScale(FLOAT_MAX_PRECISION, FLOAT_DEFAULT_PRECISION, FLOAT_DEFAULT_SCALE);
1517
                break;
1518
            case DataTypes.DOUBLE:
1519
                this.size = 0;
1520
                this.fixPrecisionAndScale(DOUBLE_MAX_PRECISION, DOUBLE_DEFAULT_PRECISION, DOUBLE_DEFAULT_SCALE);
1521
                break;
1522
            case DataTypes.DECIMAL:
1523
                this.size = 0;
1524
                this.fixPrecisionAndScale(DECIMAL_MAX_PRECISION, DECIMAL_DEFAULT_PRECISION, DECIMAL_DEFAULT_SCALE);
1525
                break;
1526
        }
1527
    }
1528

    
1529
    private void fixPrecisionAndScale(int max_precision, int default_precision, int default_scale) {
1530
      if( this.precision < 1 ) {
1531
        // Sin precision
1532
        if( this.scale < 1 ) {
1533
          // Sin precision y sin escala 
1534
          // Asinamos los valores por defecto.
1535
          this.precision = default_precision;
1536
          this.scale = default_scale;
1537
        } else {
1538
          // Sin precision y con escala.
1539
          if( this.scale <= max_precision ) {
1540
            // Sin precision y con escala < maxima precision.
1541
            // Asignamos la precision a la maxima.
1542
            this.precision = max_precision;
1543
          } else {
1544
            // Sin precision y con escala > maxima precision.
1545
            // Esto es un error.
1546
            // Asignamos la precision a la maxima y reducimos la escala
1547
            // a la maxima precision.
1548
            this.precision = max_precision;
1549
            this.scale = max_precision;
1550
          }
1551
        }
1552
      } else {
1553
        // Con precicion
1554
        if( this.scale < 1 ) {
1555
          // Con precision y sin escala.
1556
          // Esto no es del todo correto. 
1557
          // Probablemente algunos proveedores lo convertirian a int. 
1558
          // Vamos a forzar que siempre tenga 1 decimal.
1559
          if( this.precision < max_precision ) {
1560
            // Con precision < maxima precision y sin escala.
1561
            // Aumentamos la precision en 1 para a?adirle un decimal.
1562
            this.precision += 1;
1563
            this.scale = 1;
1564
          } else {
1565
            // Con precision >= maxima precision y sin escala.
1566
            // No podemos aumentar la precision para a?adirle un decimal. 
1567
            // Le a?adiremos 1 decimal, y dejaremos la precision a la maxima.
1568
            // Perdemos precision.
1569
            this.precision = max_precision;
1570
            this.scale = 1;
1571
          }
1572
        } else {
1573
         // Con precision y escala.     
1574
          if( this.precision > max_precision ) {
1575
            // Con precision mayor que la maxima y con escala.
1576
            // Reducimos la precision a la maxima.
1577
            this.precision = max_precision;
1578
          }
1579
          if( this.precision >= this.scale ) {
1580
            // Con precision y escala menor que la precision.     
1581
            // Es correcto, no hacemos nada.
1582
          } else {
1583
            // Con precision y escala mayor que la precision.
1584
            if( this.scale <= max_precision ) {
1585
              // Con precision y escala mayor que la precision y menor que la maxima precision.
1586
              // Aumentamos la precision para soportar la escala indicada.
1587
              this.precision = this.scale;
1588
            } else {
1589
              // Con precision y escala mayor que la precision y mayor que la maxima precision.
1590
              // Ponemos la maxima precision y reducimos la escala a esta.
1591
              // Perdemos precision.
1592
              this.precision = max_precision;
1593
              this.scale = max_precision;
1594
            }
1595
          }
1596
        }
1597
      }
1598
      
1599
    }
1600
    
1601
    @Override
1602
    public String[] getRequiredFieldNames() {
1603
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1604
        if( emulator==null ) {
1605
            return null;
1606
        }
1607
        return emulator.getRequiredFieldNames();
1608
    }
1609

    
1610
    @Override
1611
    public void recentUsed() {
1612
        DefaultFeatureType.RECENTS_USEDS.add(this);
1613
    }
1614

    
1615
    @Override
1616
    public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1617
        if( other == null ) {
1618
            throw new NullPointerException();
1619
        }
1620
        DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1621
        if( !StringUtils.equalsIgnoreCase(old.name, this.name) ) {
1622
            return false;
1623
        }
1624
        if( old.isComputed() && old.isComputed()==this.isComputed() ) {
1625
            return true;
1626
        }
1627
        if( this.dataType!=old.dataType ) {
1628
            return false;
1629
        }
1630
        if( this.size != old.size ) {
1631
            return false;
1632
        }
1633
        if( this.precision != old.precision ) {
1634
            return false;
1635
        }
1636
//        if( this.primaryKey != old.primaryKey ) {
1637
//            return false;
1638
//        }
1639
        if( this.geomType != old.geomType ) {
1640
            return false;
1641
        }
1642
        if( this.SRS != old.SRS ) {
1643
            return false;
1644
        }
1645
        if( this.isAutomatic != old.isAutomatic ) {
1646
            return false;
1647
        }
1648
        return true;
1649
    }
1650
    
1651
}