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

History | View | Annotate | Download (75.8 KB)

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

    
25
import java.lang.ref.WeakReference;
26
import java.math.BigDecimal;
27
import java.math.MathContext;
28
import java.math.RoundingMode;
29
import java.text.DateFormat;
30
import java.util.ArrayList;
31
import java.util.HashMap;
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 java.util.function.Supplier;
39
import javax.json.JsonObject;
40
import org.apache.commons.lang3.ArrayUtils;
41
import org.apache.commons.lang3.StringUtils;
42
import org.apache.commons.lang3.tuple.Pair;
43
import org.cresques.cts.IProjection;
44
import org.gvsig.expressionevaluator.Expression;
45
import org.gvsig.expressionevaluator.ExpressionUtils;
46
import org.gvsig.expressionevaluator.MutableSymbolTable;
47
import org.gvsig.fmap.dal.DALLocator;
48
import org.gvsig.fmap.dal.DataStore;
49
import org.gvsig.fmap.dal.DataTypes;
50
import org.gvsig.fmap.dal.expressionevaluator.FeatureAttributeEmulatorExpression;
51
import org.gvsig.fmap.dal.feature.DataProfile;
52
import org.gvsig.fmap.dal.feature.Feature;
53
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
56
import org.gvsig.fmap.dal.feature.FeatureStore;
57
import org.gvsig.fmap.dal.feature.FeatureType;
58
import org.gvsig.fmap.dal.feature.ForeingKey;
59
import org.gvsig.fmap.dal.feature.ForeingKey.ContextForeingKey;
60
import org.gvsig.fmap.geom.Geometry;
61
import org.gvsig.fmap.geom.GeometryCoercionContext;
62
import org.gvsig.fmap.geom.GeometryException;
63
import org.gvsig.fmap.geom.GeometryLocator;
64
import org.gvsig.fmap.geom.GeometryUtils;
65
import org.gvsig.fmap.geom.type.GeometryType;
66
import org.gvsig.json.Json;
67
import org.gvsig.json.JsonManager;
68
import org.gvsig.json.JsonObjectBuilder;
69
import org.gvsig.json.SupportToJson;
70
import org.gvsig.timesupport.Interval;
71
import org.gvsig.timesupport.RelativeInterval;
72
import org.gvsig.timesupport.TimeSupportLocator;
73
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.dataTypes.Coercion;
75
import org.gvsig.tools.dataTypes.CoercionContext;
76
import org.gvsig.tools.dataTypes.CoercionException;
77
import org.gvsig.tools.dataTypes.DataType;
78
import org.gvsig.tools.dataTypes.DataType.NumberPrecisionAndScale;
79
import org.gvsig.tools.dataTypes.DataTypeUtils;
80
import org.gvsig.tools.dynobject.AbstractDynMethod;
81
import org.gvsig.tools.dynobject.DynField;
82
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
83
import org.gvsig.tools.dynobject.DynField_v2;
84
import org.gvsig.tools.dynobject.DynMethod;
85
import org.gvsig.tools.dynobject.DynObject;
86
import org.gvsig.tools.dynobject.DynObjectValueItem;
87
import org.gvsig.tools.dynobject.DynStruct;
88
import org.gvsig.tools.dynobject.Tags;
89
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
90
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
91
import org.gvsig.tools.dynobject.exception.DynMethodException;
92
import org.gvsig.tools.dynobject.impl.DefaultTags;
93
import org.gvsig.tools.evaluator.AbstractEvaluator;
94
import org.gvsig.tools.evaluator.Evaluator;
95
import org.gvsig.tools.evaluator.EvaluatorData;
96
import org.gvsig.tools.evaluator.EvaluatorException;
97
import org.gvsig.tools.i18n.I18nManager;
98
import org.gvsig.tools.persistence.PersistenceManager;
99
import org.gvsig.tools.persistence.Persistent;
100
import org.gvsig.tools.persistence.PersistentState;
101
import org.gvsig.tools.persistence.exception.PersistenceException;
102
import org.gvsig.tools.util.GetItemWithSize;
103
import org.gvsig.tools.util.LabeledValue;
104
import org.slf4j.Logger;
105
import org.slf4j.LoggerFactory;
106

    
107
@SuppressWarnings("UseSpecificCatch")
108
public class DefaultFeatureAttributeDescriptor implements
109
        FeatureAttributeDescriptor, Persistent, DynField_v2, DynField_LabelAttribute {
110

    
111
    protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureAttributeDescriptor.class);
112

    
113
    protected boolean allowNull;
114
    protected DataType dataType;
115
    protected String dataProfile;
116
    protected DateFormat dateFormat;
117
    protected Object defaultValue;
118
    protected int index;
119
    protected int maximumOccurrences;
120
    protected int minimumOccurrences;
121
    protected int size;
122
    protected String name;
123
    protected Class objectClass;
124
    protected int precision;
125
    protected int scale;
126
    protected int roundMode;
127
    protected Evaluator evaluator;
128
    protected boolean primaryKey;
129
    protected boolean readOnly;
130
    protected IProjection SRS;
131
    protected GeometryType geomType;
132
    protected int geometryType;
133
    protected int geometrySubType;
134
    protected Map<String, String> additionalInfo;
135
    protected boolean isAutomatic;
136
    protected boolean isTime = false;
137
    protected Interval interval;
138
    protected FeatureAttributeGetter featureAttributeGetter = null;
139
    protected FeatureAttributeEmulator featureAttributeEmulator = null;
140
    protected boolean indexed = false;
141
    protected boolean isIndexAscending = true;
142
    protected boolean allowIndexDuplicateds = true;
143

    
144
    protected DynObjectValueItem[] availableValues;
145
    protected DynObjectValueItem[] availableValuesCache; // No persistente
146
    protected Expression availableValuesExpression;
147
    protected boolean avoidCachingAvailableValues;
148
    private Map<Object, String> labelOfValueMap; // No persistente
149
    protected String description;
150
    protected Object minValue;
151
    protected Object maxValue;
152
    protected String label;
153
    protected String shortLabel;
154
    protected int order;
155
    protected boolean hidden;
156
    protected String groupName;
157
    protected Tags tags = new DefaultTags();
158
    private DynMethod availableValuesMethod;
159
    private DynMethod calculateMethod;
160
    private WeakReference typeRef;
161
    protected DefaultForeingKey foreingKey = null;
162

    
163
    protected CoercionContext coerceContext = null; // not persistent
164
    protected MathContext mathContext = null; // not persistent
165

    
166
    private int relationType = RELATION_TYPE_NONE;
167
    protected Locale locale;
168
    protected int displaySize;
169

    
170
    public DefaultFeatureAttributeDescriptor() {
171
        // Usada en la persistencia
172
        this.precision = DataType.PRECISION_NONE;
173
        this.scale = DataType.SCALE_NONE;
174
        this.roundMode = BigDecimal.ROUND_HALF_UP;
175
    }
176

    
177
    protected DefaultFeatureAttributeDescriptor(FeatureType type) {
178
        this();
179
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x].", this.hashCode()));
180
        setFeatureType(type);
181
        this.allowNull = true;
182
        this.dataType = null;
183
        this.dateFormat = null;
184
        this.defaultValue = null;
185
        this.index = -1;
186
        this.maximumOccurrences = 0;
187
        this.minimumOccurrences = 0;
188
        this.size = 0;
189
        this.name = null;
190
        this.objectClass = null;
191
        this.precision = DataType.PRECISION_NONE;
192
        this.scale = DataType.SCALE_NONE;
193
        this.roundMode = BigDecimal.ROUND_HALF_UP;
194
        this.evaluator = null;
195
        this.primaryKey = false;
196
        this.readOnly = false;
197
        this.SRS = null;
198
        this.geometryType = Geometry.TYPES.NULL;
199
        this.geometrySubType = Geometry.SUBTYPES.UNKNOWN;
200
        this.additionalInfo = null;
201
        this.isAutomatic = false;
202
        this.hidden = false;
203
        this.relationType = RELATION_TYPE_NONE;
204
        this.locale = null;
205
        this.displaySize = 0;
206
        this.avoidCachingAvailableValues = false;
207
    }
208

    
209
    protected DefaultFeatureAttributeDescriptor(
210
            DefaultFeatureAttributeDescriptor other
211
    ) {
212
        this();
213
        copyFrom(other);
214
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x] [%s] (copy).", this.hashCode(), this.name));
215
    }
216

    
217
    @Override
218
    public void copyFrom(DynField other1) {
219
        if (!(other1 instanceof DefaultFeatureAttributeDescriptor)) {
220
            throw new IllegalArgumentException("Can't copy from a non DefaultFeatureAttributeDescriptor");
221
        }
222
        DefaultFeatureAttributeDescriptor other = (DefaultFeatureAttributeDescriptor) other1;
223
        this.typeRef = other.typeRef;
224
        this.allowNull = other.allowNull;
225
        this.dataType = other.dataType;
226
        this.dateFormat = other.dateFormat;
227
        this.defaultValue = other.defaultValue;
228
        this.index = other.index;
229
        this.maximumOccurrences = other.maximumOccurrences;
230
        this.minimumOccurrences = other.minimumOccurrences;
231
        this.size = other.size;
232
        this.name = other.name;
233
        this.objectClass = other.objectClass;
234
        this.precision = other.precision;
235
        this.scale = other.scale;
236
        this.roundMode = other.roundMode;
237
        this.evaluator = other.evaluator;
238
        this.primaryKey = other.primaryKey;
239
        this.readOnly = other.readOnly;
240
        this.SRS = other.SRS;
241
        this.geometryType = other.geometryType;
242
        this.geometrySubType = other.geometrySubType;
243
        this.geomType = other.geomType;
244
        if (other.additionalInfo != null) {
245
            this.additionalInfo = new HashMap();
246
            for (Entry<String, String> entry : other.additionalInfo.entrySet()) {
247
                this.additionalInfo.put(entry.getKey(), entry.getValue());
248
            }
249
        } else {
250
            this.additionalInfo = null;
251
        }
252
        this.isAutomatic = other.isAutomatic;
253
        this.isTime = other.isTime;
254
        this.featureAttributeEmulator = other.featureAttributeEmulator;
255
        this.indexed = other.indexed;
256
        this.isIndexAscending = other.isIndexAscending;
257
        this.allowIndexDuplicateds = other.allowIndexDuplicateds;
258
        this.hidden = other.hidden;
259
        this.dataProfile = other.dataProfile;
260

    
261
        this.availableValues = other.availableValues;
262
        this.availableValuesExpression = other.availableValuesExpression;
263
        this.description = other.description;
264
        this.minValue = other.minValue;
265
        this.maxValue = other.maxValue;
266
        this.label = other.label;
267
        this.order = other.order;
268
        this.groupName = other.groupName;
269
        if (other.tags == null) {
270
            this.tags = null;
271
        } else {
272
            try {
273
                this.tags = (Tags) other.tags.clone();
274
            } catch (Exception ex) {
275
            }
276
        }
277
        this.foreingKey = null;
278
        if (other.foreingKey != null) {
279
            try {
280
                this.foreingKey = (DefaultForeingKey) other.foreingKey.clone();
281
            } catch (CloneNotSupportedException ex) {
282
            }
283
        }
284
        if (this.foreingKey != null) {
285
            this.foreingKey.setDescriptor(this);
286
        }
287

    
288
        // TODO: ? Habria que clonarlos ?
289
        this.availableValuesMethod = other.availableValuesMethod;
290
        this.calculateMethod = other.calculateMethod;
291
        this.relationType = other.relationType;
292
        this.locale = other.locale;
293
        this.displaySize = other.displaySize;
294
        this.avoidCachingAvailableValues = other.avoidCachingAvailableValues;
295
    }
296

    
297
    public void setFeatureType(FeatureType type) {
298
        // Usada en la persistencia
299
        if (type == null) {
300
            this.typeRef = null;
301
        } else {
302
            this.typeRef = new WeakReference(type);
303
//            LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set FeatureType [%08x], ref [%08x].", this.hashCode(), type.hashCode(), typeRef.hashCode()));
304
        }
305
    }
306

    
307
    @Override
308
    public String getDataTypeName() {
309
        if (this.getDataType() == null) {
310
            return "(unknow)";
311
        }
312
        return this.getDataType().getName();
313
    }
314

    
315
    @Override
316
    public DefaultFeatureAttributeDescriptor getCopy() {
317
        return new DefaultFeatureAttributeDescriptor(this);
318
    }
319

    
320
    @Override
321
    public Object clone() throws CloneNotSupportedException {
322
        return new DefaultFeatureAttributeDescriptor(this);
323
    }
324

    
325
    @Override
326
    public boolean allowNull() {
327
        return allowNull;
328
    }
329

    
330
    @Override
331
    public Locale getLocale() {
332
        if (this.locale == null) {
333
            if (this.dataType.isNumeric()) {
334
                this.locale = Locale.ENGLISH;
335
            } else {
336
                this.locale = Locale.getDefault();
337
            }
338
        }
339
        return this.locale;
340
    }
341

    
342
    @Override
343
    public DataType getDataType() {
344
        if (featureAttributeGetter != null) {
345
            return featureAttributeGetter.getDataType();
346
        }
347
        return this.dataType;
348
    }
349

    
350
    public FeatureAttributeDescriptor setDataType(int type) {
351
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
352
        return this;
353
    }
354

    
355
    @Override
356
    public DateFormat getDateFormat() {
357
        return this.dateFormat;
358
    }
359

    
360
    @Override
361
    public Object getDefaultValue() {
362
        return this.defaultValue;
363
    }
364

    
365
    @Override
366
    @Deprecated
367
    public Object getDefaultValueCoerced() {
368
        return getCoercedDefaultValue();
369
    }
370

    
371
    @Override
372
    public Object getCoercedDefaultValue() {
373
        try {
374
            Object value = this.defaultValue;
375
            if (value == null) {
376
                return null;
377
            }
378
            if (ExpressionUtils.isDynamicText(value.toString())) {
379
                value = ExpressionUtils.evaluateDynamicText(value.toString());
380
            }
381
            return this.getDataType().coerce(value);
382
        } catch (CoercionException ex) {
383
            return null;
384
        }
385
    }
386

    
387
    @Override
388
    public Supplier getDefaultValueSupplier() {
389
        return (Supplier) this::getDefaultValueCoerced;
390
    }
391

    
392
    @Override
393
    public DynField setDefaultValueSupplier(Supplier supplier) {
394
        //Do nothing
395
        return this;
396
    }
397

    
398
    @Override
399
    public Evaluator getEvaluator() {
400
        return this.evaluator;
401
    }
402

    
403
    @Override
404
    public int getGeometryType() {
405
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
406
            return Geometry.TYPES.UNKNOWN;
407
        }
408
        return this.geometryType;
409
    }
410

    
411
    @Override
412
    public int getGeometrySubType() {
413
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
414
            return Geometry.SUBTYPES.UNKNOWN;
415
        }
416
        return this.geometrySubType;
417
    }
418

    
419
    @Override
420
    public GeometryType getGeomType() {
421
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
422
            return null;
423
        }
424
        if (this.geomType == null) {
425
            try {
426
                this.geomType
427
                        = GeometryLocator.getGeometryManager().getGeometryType(
428
                                this.geometryType, this.geometrySubType);
429
            } catch (GeometryException e) {
430
                throw new RuntimeException(
431
                        "Error getting geometry type with type = "
432
                        + this.geometryType + ", subtype = "
433
                        + this.geometrySubType, e);
434
            }
435
        }
436
        return this.geomType;
437
    }
438

    
439
    @Override
440
    public int getIndex() {
441
        return this.index;
442
    }
443

    
444
    protected FeatureAttributeDescriptor setIndex(int index) {
445
        this.index = index;
446
        return this;
447
    }
448

    
449
    @Override
450
    public int getMaximumOccurrences() {
451
        return this.maximumOccurrences;
452
    }
453

    
454
    @Override
455
    public int getMinimumOccurrences() {
456
        return this.minimumOccurrences;
457
    }
458

    
459
    @Override
460
    public String getName() {
461
        return this.name;
462
    }
463

    
464
    public FeatureAttributeDescriptor setName(String name) {
465
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
466
        this.name = name;
467
        return this;
468
    }
469

    
470
    @Override
471
    public Class getObjectClass() {
472
        if (getDataType().getType() == DataTypes.OBJECT) {
473
            return objectClass;
474
        }
475
        return getDataType().getDefaultClass();
476
    }
477

    
478
    @Override
479
    public int getPrecision() {
480
        return this.precision;
481
    }
482

    
483
    @Override
484
    public int getScale() {
485
        return this.scale;
486
    }
487

    
488
    @Override
489
    public Coercion getCoercion() {
490
        return this.getDataType().getCoercion();
491
    }
492

    
493
    @Override
494
    public MathContext getMathContext() {
495
        if (this.mathContext == null) {
496
            if (this.getDataType().isNumeric()) {
497
                this.mathContext = new MathContext(
498
                        this.getPrecision(),
499
                        RoundingMode.valueOf(this.getRoundMode())
500
                );
501
            } else {
502
                this.mathContext = MathContext.UNLIMITED;
503
            }
504
        }
505
        return this.mathContext;
506
    }
507

    
508
    @Override
509
    public CoercionContext getCoercionContext() {
510
        if (this.coerceContext == null) {
511
            if (this.getDataType().isNumeric()) {
512
                this.coerceContext = DataTypeUtils.coerceContextDecimal(
513
                        this.getLocale(),
514
                        this.getPrecision(),
515
                        this.getScale(),
516
                        this.getRoundMode()
517
                );
518
            } else if (this.getType() == DataTypes.GEOMETRY) {
519
                GeometryCoercionContext context = GeometryLocator.getGeometryManager().createGeometryCoercionContext();
520
                context.setGeometryType(this.getGeomType());
521
                context.setMode(GeometryCoercionContext.MODE_ONERROR_DONTCONVERT);
522
                this.coerceContext = context;
523
            } else {
524
                this.coerceContext = DataTypeUtils.coerceContextLocale(
525
                        this.getLocale()
526
                );
527
            }
528
        }
529
        return this.coerceContext;
530
    }
531

    
532
    @Override
533
    public int getRoundMode() {
534
        return this.roundMode;
535
    }
536

    
537
    @Override
538
    public IProjection getSRS() {
539
        return this.SRS;
540
    }
541

    
542
    @Override
543
    public Interval getInterval() {
544
        return this.interval;
545
    }
546

    
547
    public IProjection getSRS(WeakReference storeRef) {
548
        if (this.SRS == null) {
549
            FeatureStore store = (FeatureStore) storeRef.get();
550
            this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
551
        }
552
        return this.SRS;
553
    }
554

    
555
    @Override
556
    public int getSize() {
557
        return this.size;
558
    }
559

    
560
    @Override
561
    public boolean isPrimaryKey() {
562
        return this.primaryKey;
563
    }
564

    
565
    @Override
566
    public boolean isReadOnly() {
567
        if (this.readOnly) {
568
            return true;
569
        }
570
        return this.isComputed();
571
    }
572

    
573
    @Override
574
    public String getAdditionalInfo(String infoName) {
575
        if (this.additionalInfo == null) {
576
            return null;
577
        }
578
        return this.additionalInfo.get(infoName);
579
    }
580

    
581
    @Override
582
    public boolean isAutomatic() {
583
        return this.isAutomatic;
584
    }
585

    
586
    @Override
587
    public boolean equals(Object obj) {
588
        if (this == obj) {
589
            return true;
590
        }
591
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
592
            return false;
593
        }
594
        DefaultFeatureAttributeDescriptor other
595
                = (DefaultFeatureAttributeDescriptor) obj;
596

    
597
        if (this.allowNull != other.allowNull) {
598
            return false;
599
        }
600

    
601
        if (this.index != other.index) {
602
            return false;
603
        }
604

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

    
609
        if (this.getDataType() != other.getDataType()) {
610
            return false;
611
        }
612

    
613
        if (this.size != other.size) {
614
            return false;
615
        }
616

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

    
621
        if (this.primaryKey != other.primaryKey) {
622
            return false;
623
        }
624

    
625
        if (this.isAutomatic != other.isAutomatic) {
626
            return false;
627
        }
628

    
629
        if (this.readOnly != other.readOnly) {
630
            return false;
631
        }
632

    
633
        if (this.precision != other.precision) {
634
            return false;
635
        }
636

    
637
        if (this.maximumOccurrences != other.maximumOccurrences) {
638
            return false;
639
        }
640

    
641
        if (this.minimumOccurrences != other.minimumOccurrences) {
642
            return false;
643
        }
644

    
645
        if (this.geometryType != other.geometryType) {
646
            return false;
647
        }
648

    
649
        if (this.geometrySubType != other.geometrySubType) {
650
            return false;
651
        }
652

    
653
        if (!Objects.equals(this.evaluator, other.evaluator)) {
654
            return false;
655
        }
656

    
657
        if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
658
            return false;
659
        }
660

    
661
        if (!Objects.equals(this.SRS, other.SRS)) {
662
            return false;
663
        }
664

    
665
        if (!Objects.equals(this.dateFormat, other.dateFormat)) {
666
            return false;
667
        }
668

    
669
        if (!Objects.equals(this.objectClass, other.objectClass)) {
670
            return false;
671
        }
672

    
673
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
674
            return false;
675
        }
676

    
677
        return true;
678
    }
679

    
680
    @Override
681
    public void loadFromState(PersistentState state)
682
            throws PersistenceException {
683
        allowNull = state.getBoolean("allowNull");
684
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
685
        dataProfile = state.getString("dataProfile");
686

    
687
//        FIXME: dateFormat;
688
        try {
689
            defaultValue = dataType.coerce(state.get("defaultValue"));
690
        } catch (CoercionException ex) {
691
        }
692

    
693
        index = state.getInt("index");
694
        maximumOccurrences = state.getInt("maximumOccurrences");
695
        minimumOccurrences = state.getInt("minimumOccurrences");
696
        size = state.getInt("size");
697
        name = state.getString("name");
698
        try {
699
            String objectClassName = state.getString("objectClass");
700
            if (!StringUtils.isBlank(objectClassName)) {
701
                objectClass = Class.forName(objectClassName);
702
            }
703
        } catch (Throwable e) {
704
            LOGGER.warn("Can't restore the objectClass of the FeatureAttributreDescriptor", e);
705
        }
706
        precision = state.getInt("precision");
707
        scale = state.getInt("scale");
708
        roundMode = state.getInt("roundMode");
709
        String locale_s = state.getString("locale");
710
        locale = (StringUtils.isBlank(locale_s) || "null".equalsIgnoreCase(locale_s)) ? null : Locale.forLanguageTag(locale_s);
711
        evaluator = (Evaluator) state.get("evaluator");
712
        primaryKey = state.getBoolean("primaryKey");
713
        readOnly = state.getBoolean("readOnly");
714
        SRS = (IProjection) state.get("SRS");
715
        geometryType = state.getInt("geometryType");
716
        geometrySubType = state.getInt("geometrySubType");
717
        if (geometryType != Geometry.TYPES.UNKNOWN
718
                && geometrySubType != Geometry.SUBTYPES.UNKNOWN) {
719
            geomType = GeometryUtils.getGeometryType(
720
                    geometryType,
721
                    geometrySubType
722
            );
723
        }
724
//        additionalInfo = (Map) state.get("aditionalInfo");
725
        isAutomatic = state.getBoolean("isAutomatic");
726
        isTime = state.getBoolean("isTime");
727
        if (state.hasValue("intervalStart")) {
728
            long intervalStart = state.getLong("interval_start");
729
            long intervalEnd = state.getLong("interval_end");
730
            interval = TimeSupportLocator.getManager().createRelativeInterval(intervalStart, intervalEnd);
731
        } else {
732
            interval = null;
733
        }
734
        featureAttributeEmulator = (FeatureAttributeEmulator) state.get("featureAttributeEmulator");
735
        indexed = state.getBoolean("indexed");
736
        isIndexAscending = state.getBoolean("isIndexAscending");
737
        allowIndexDuplicateds = state.getBoolean("allowIndexDuplicateds");
738

    
739
        Map<String, Object> values = state.getMap("availableValues");
740
        if (values == null || values.isEmpty()) {
741
            this.availableValues = null;
742
        } else {
743
            this.availableValues = new DynObjectValueItem[values.size()];
744
            int n = 0;
745
            for (Entry<String, Object> entry : values.entrySet()) {
746
                this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
747
            }
748
        }
749

    
750
        description = state.getString("description");
751
        minValue = state.get("minValue");
752
        maxValue = state.get("maxValue");
753
        label = state.getString("label");
754
        order = state.getInt("order");
755
        hidden = state.getBoolean("hidden");
756
        groupName = state.getString("groupName");
757
        relationType = state.getInt("relationType", RELATION_TYPE_NONE);
758

    
759
        foreingKey = (DefaultForeingKey) state.get("foreingKey");
760
        if (foreingKey != null) {
761
            this.foreingKey.setDescriptor(this);
762
        }
763
        tags = (Tags) state.get("tags");
764
        if (tags == null) {
765
            this.tags = new DefaultTags();
766
        }
767
        displaySize = state.getInt("displaySize", 0);
768
        availableValuesExpression = (Expression) state.get("availableValuesExpression");
769
        avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues", false);
770
        availableValuesCache = null;
771

    
772
    }
773

    
774
    @Override
775
    public void saveToState(PersistentState state) throws PersistenceException {
776
        Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
777

    
778
        state.set("allowNull", allowNull);
779
        state.set("dataType", dataType.getType());
780
        state.set("dataProfile", dataProfile);
781

    
782
//        FIXME: dateFormat;
783
        state.set("defaultValue", Objects.toString(defaultValue, null));
784

    
785
        state.set("index", index);
786
        state.set("maximumOccurrences", maximumOccurrences);
787
        state.set("minimumOccurrences", minimumOccurrences);
788
        state.set("size", size);
789
        state.set("name", name);
790
        state.set("objectClass", objectClass == null ? null : objectClass.getName());
791
        state.set("precision", precision);
792
        state.set("scale", scale);
793
        state.set("roundMode", roundMode);
794
        if (this.locale == null) {
795
            state.setNull("locale");
796
        } else {
797
            state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
798
        }
799
        state.set("evaluator", evaluator);
800

    
801
        state.set("primaryKey", primaryKey);
802
        state.set("readOnly", readOnly);
803
        state.set("SRS", SRS);
804
        GeometryType theGeomType = this.getGeomType();
805
        if (theGeomType == null) {
806
            state.set("geometryType", Geometry.TYPES.UNKNOWN);
807
            state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
808
        } else {
809
            state.set("geometryType", theGeomType.getType());
810
            state.set("geometrySubType", theGeomType.getSubType());
811
        }
812

    
813
//      FIXME: additionalInfo
814
        state.set("isAutomatic", isAutomatic);
815
        state.set("isTime", isTime);
816
        if (this.interval == null) {
817
            state.setNull("interval_start");
818
            state.setNull("interval_end");
819
        } else {
820
            state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
821
            state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
822
        }
823
        state.set("SRS", SRS);
824

    
825
//      FIXME: featureAttributeGetter
826
        if (featureAttributeEmulator instanceof Persistent) {
827
            state.set("featureAttributeEmulator", featureAttributeEmulator);
828
        } else {
829
            state.setNull("featureAttributeEmulator");
830
        }
831

    
832
        state.set("indexed", indexed);
833
        state.set("isIndexAscending", isIndexAscending);
834
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
835

    
836
        if (this.availableValues == null) {
837
            state.setNull("availableValues");
838
        } else {
839
            Map<String, Object> values = new LinkedHashMap<>();
840
            for (DynObjectValueItem value : availableValues) {
841
                values.put(value.getLabel(), value.getValue());
842
            }
843
            state.set("availableValues", values);
844
        }
845
        state.set("description", description);
846
        state.set("minValue", minValue);
847
        state.set("maxValue", maxValue);
848
        state.set("label", label);
849
        state.set("order", order);
850
        state.set("hidden", hidden);
851
        state.set("groupName", groupName);
852
        state.set("relationType", relationType);
853

    
854
        state.set("foreingKey", this.foreingKey);
855
        state.set("tags", this.tags);
856

    
857
        state.set("displaySize", displaySize);
858
        state.set("availableValuesExpression", availableValuesExpression);
859
        state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);
860
    }
861

    
862
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
863

    
864
    public static void registerPersistenceDefinition() {
865
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
866

    
867
        if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
868
                == null) {
869
            DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
870
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
871
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
872
                    + " persistent definition",
873
                    null,
874
                    null
875
            );
876
            definition.addDynFieldBoolean("allowNull");
877
            definition.addDynFieldInt("dataType");
878
            definition.addDynFieldString("dataProfile");
879
//            definition.addDynFieldString("dateFormat");
880
            definition.addDynFieldString("defaultValue");
881
            definition.addDynFieldInt("index");
882
            definition.addDynFieldInt("maximumOccurrences");
883
            definition.addDynFieldInt("minimumOccurrences");
884
            definition.addDynFieldInt("size");
885
            definition.addDynFieldString("name");
886
            definition.addDynFieldString("objectClass");
887
            definition.addDynFieldInt("precision");
888
            definition.addDynFieldInt("scale").setMandatory(false).setDefaultDynValue(DataType.SCALE_NONE);
889
            definition.addDynFieldInt("roundMode").setMandatory(false).setDefaultDynValue(BigDecimal.ROUND_HALF_UP);
890
            definition.addDynFieldString("locale").setMandatory(false).setDefaultDynValue("null");
891
            definition.addDynFieldObject("evaluator").setClassOfValue(Evaluator.class);
892
            definition.addDynFieldBoolean("primaryKey");
893
            definition.addDynFieldBoolean("readOnly");
894
            definition.addDynFieldObject("SRS")
895
                    .setClassOfValue(IProjection.class);
896
            definition.addDynFieldInt("geometryType");
897
            definition.addDynFieldInt("geometrySubType");
898
//            definition.addDynFieldMap("additionalInfo");
899
            definition.addDynFieldBoolean("isAutomatic");
900
            definition.addDynFieldBoolean("isTime");
901
            definition.addDynFieldLong("interval_start");
902
            definition.addDynFieldLong("interval_end");
903
            definition.addDynFieldObject("featureAttributeEmulator")
904
                    .setClassOfValue(FeatureAttributeEmulator.class);
905
            definition.addDynFieldBoolean("indexed");
906
            definition.addDynFieldBoolean("isIndexAscending");
907
            definition.addDynFieldBoolean("allowIndexDuplicateds");
908
            definition.addDynFieldMap("availableValues")
909
                    .setClassOfItems(Object.class);
910
            definition.addDynFieldString("description");
911
            definition.addDynFieldObject("minValue");
912
            definition.addDynFieldObject("maxValue");
913
            definition.addDynFieldString("label");
914
            definition.addDynFieldInt("order");
915
            definition.addDynFieldBoolean("hidden");
916
            definition.addDynFieldBoolean("avoidCachingAvailableValues");
917
            definition.addDynFieldString("groupName");
918
            definition.addDynFieldInt("relationType");
919

    
920
            definition.addDynFieldObject("foreingKey")
921
                    .setClassOfValue(DefaultForeingKey.class);
922

    
923
            definition.addDynFieldObject("tags")
924
                    .setClassOfValue(Tags.class);
925

    
926
            definition.addDynFieldInt("displaySize").setMandatory(false);
927
            definition.addDynFieldObject("availableValuesExpression")
928
                    .setClassOfValue(Expression.class)
929
                    .setMandatory(false);
930
        }
931
    }
932

    
933
    /*
934
     * Start of DynField interface Implementation
935
     *
936
     */
937
    @Override
938
    public Tags getTags() {
939
        return tags;
940
    }
941

    
942
    private Expression availableValuesFilter;
943

    
944
    @Override
945
    public Expression getAvailableValuesFilter() {
946
        return this.availableValuesFilter;
947
    }
948

    
949
    public FeatureAttributeDescriptor setAvailableValuesFilter(Expression filter) {
950
        this.availableValuesFilter = filter;
951
        return this;
952
    }
953

    
954
    public FeatureAttributeDescriptor setAvailableValuesFilter(String filter) {
955
        this.availableValuesFilter = ExpressionUtils.createExpression(filter);
956
        return this;
957
    }
958

    
959
    @Override
960
    public boolean hasConstantAvailableValues() {
961
        return this.availableValues != null;
962
    }
963

    
964
    @Override
965
    public boolean isAvoidCachingAvailableValues() {
966
        return this.avoidCachingAvailableValues;
967
    }
968

    
969
    public boolean hasAvailableValues() {
970
        return getAvailableValues() != null;
971
    }
972

    
973
    @Override
974
    public DynObjectValueItem[] getAvailableValues(DynObject context) {
975
        if (this.availableValuesMethod != null) {
976
            DynObjectValueItem[] values;
977
            try {
978
                values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(context, new Object[]{this});
979
            } catch (DynMethodException ex) {
980
                return this.getAvailableValues();
981
            }
982
            if (values != null) {
983
                return values;
984
            }
985
        }
986
        Expression filter = this.availableValuesFilter;
987
        if (!ExpressionUtils.isEmpty(filter)) {
988
            if (this.isForeingKey() && this.foreingKey.isClosedList()) {
989
                ContextForeingKey foreingkeyContext = this.foreingKey.createContext();
990
                foreingkeyContext.setContextValues(context);
991
                DynObjectValueItem[] values = this.foreingKey.getAvailableValues(foreingkeyContext);
992
                return values;
993
            }
994
            MutableSymbolTable contextSymbolTable = ExpressionUtils.createSymbolTable("feature", context);
995
            MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
996
            symbolTable.addSymbolTable(contextSymbolTable);
997

    
998
            DynObjectValueItem[] allValues = this.getAvailableValues();
999
            List<DynObjectValueItem> filteredValues = new ArrayList<>();
1000
            for (DynObjectValueItem value : allValues) {
1001
                symbolTable.setVar("$value", value.getValue());
1002
                symbolTable.setVar("$label", value.getLabel());
1003
                Object include = filter.execute(symbolTable);
1004
                if (DataTypeUtils.isFalse(include, false)) {
1005
                    continue;
1006
                }
1007
                filteredValues.add(value);
1008
            }
1009
            DynObjectValueItem[] values = filteredValues.toArray(
1010
                    new DynObjectValueItem[filteredValues.size()]
1011
            );
1012
            return values;
1013
        }
1014
        return this.getAvailableValues();
1015
    }
1016

    
1017
    @Override
1018
    public boolean isAvailableValuesCalculated() {
1019
        if (this.availableValuesMethod != null) {
1020
            return true;
1021
        }
1022
        if (!ExpressionUtils.isEmpty(this.availableValuesFilter)) {
1023
            return true;
1024
        }
1025
        return false;
1026
    }
1027

    
1028
    @Override
1029
    public DynObjectValueItem[] getAvailableValues() {
1030
        DynObjectValueItem[] values = this.availableValues;
1031

    
1032
        if (values != null) {
1033
            return values;
1034
        }
1035
        values = this.availableValuesCache;
1036
        if (values != null) {
1037
            return values;
1038
        }
1039
        if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1040
            values = this.foreingKey.getAvailableValues(null);
1041

    
1042
        } else if (this.availableValuesExpression != null) {
1043
            values = this.getAvailableValuesFromExpression();
1044
        }
1045
        if (!this.avoidCachingAvailableValues) {
1046
            this.availableValuesCache = values;
1047
        }
1048
        return values;
1049
    }
1050

    
1051
    private DynObjectValueItem[] getAvailableValuesFrom(GetItemWithSize values) {
1052
        if (values.size() == 0) {
1053
            return null;
1054
        }
1055
        DynObjectValueItem[] r = null;
1056
        Object firstelement = values.get(0);
1057
        if (firstelement instanceof LabeledValue) {
1058
            r = new DynObjectValueItem[values.size()];
1059
            for (int i = 0; i < values.size(); i++) {
1060
                LabeledValue v = (LabeledValue) values.get(i);
1061
                r[i] = new DynObjectValueItem(
1062
                        v.getValue(),
1063
                        Objects.toString(v.getLabel(), Objects.toString(v.getValue(), String.valueOf(i)))
1064
                );
1065
            }
1066
        } else if (firstelement instanceof Pair) {
1067
            r = new DynObjectValueItem[values.size()];
1068
            for (int i = 0; i < values.size(); i++) {
1069
                Pair v = (Pair) values.get(i);
1070
                r[i] = new DynObjectValueItem(
1071
                        v.getValue(),
1072
                        Objects.toString(v.getKey(), Objects.toString(v.getValue(), String.valueOf(i)))
1073
                );
1074
            }
1075
        } else if (firstelement instanceof JsonObject) {
1076
            JsonObject v = (JsonObject) firstelement;
1077
            String labelname = null;
1078
            for (String theName : new String[]{
1079
                "name", "label", "key", "description"
1080
            }) {
1081
                if (v.containsKey(theName)) {
1082
                    labelname = theName;
1083
                    break;
1084
                }
1085
                if (v.containsKey(theName.toUpperCase())) {
1086
                    labelname = theName.toLowerCase();
1087
                    break;
1088
                }
1089
            }
1090
            String valuename = null;
1091
            if (v.containsKey("value")) {
1092
                valuename = "value";
1093
            }
1094
            r = new DynObjectValueItem[values.size()];
1095
            for (int i = 0; i < values.size(); i++) {
1096
                v = (JsonObject) values.get(i);
1097
                String theLabel;
1098
                Object theValue;
1099
                if (labelname == null) {
1100
                    theLabel = v.toString();
1101
                } else {
1102
                    theLabel = v.getString(labelname);
1103
                }
1104
                if (valuename == null) {
1105
                    theValue = v.getString(valuename);
1106
                } else {
1107
                    theValue = v;
1108
                }
1109
                r[i] = new DynObjectValueItem(theValue, theLabel);
1110
            }
1111
        } else if (firstelement instanceof Map) {
1112
            Map<String, Object> v = (Map<String, Object>) firstelement;
1113
            String labelname = null;
1114
            for (String theName : new String[]{
1115
                "name", "label", "key", "description"
1116
            }) {
1117
                if (v.containsKey(theName)) {
1118
                    labelname = theName;
1119
                    break;
1120
                }
1121
                if (v.containsKey(theName.toUpperCase())) {
1122
                    labelname = theName.toLowerCase();
1123
                    break;
1124
                }
1125
            }
1126
            String valuename = null;
1127
            if (v.containsKey("value")) {
1128
                valuename = "value";
1129
            }
1130
            r = new DynObjectValueItem[values.size()];
1131
            for (int i = 0; i < values.size(); i++) {
1132
                v = (Map<String, Object>) values.get(i);
1133
                String theLabel;
1134
                Object theValue;
1135
                if (labelname == null) {
1136
                    theLabel = v.toString();
1137
                } else {
1138
                    theLabel = (String) v.get(labelname);
1139
                }
1140
                if (valuename == null) {
1141
                    theValue = v;
1142
                } else {
1143
                    theValue = v.get(valuename);
1144
                }
1145
                r[i] = new DynObjectValueItem(theValue, theLabel);
1146
            }
1147
        } else if (firstelement instanceof Feature) {
1148
            Feature v = (Feature) firstelement;
1149
            FeatureType featureType = v.getType();
1150
            String valuename = null;
1151
            FeatureAttributeDescriptor[] pks = featureType.getPrimaryKey();
1152
            if (pks != null && pks.length == 1) {
1153
                valuename = pks[0].getName();
1154
            }
1155
            String labelname = null;
1156
            for (String theName : new String[]{
1157
                "name", "label", "key", "description"
1158
            }) {
1159
                if (featureType.get(theName) != null) {
1160
                    labelname = theName;
1161
                    break;
1162
                }
1163
            }
1164
            r = new DynObjectValueItem[values.size()];
1165
            for (int i = 0; i < values.size(); i++) {
1166
                v = (Feature) values.get(i);
1167
                String theLabel;
1168
                Object theValue;
1169
                if (labelname == null) {
1170
                    theLabel = v.toString();
1171
                } else {
1172
                    theLabel = v.getString(labelname);
1173
                }
1174
                if (valuename == null) {
1175
                    theValue = v.getReference().getCode();
1176
                } else {
1177
                    theValue = v.get(valuename);
1178
                }
1179
                r[i] = new DynObjectValueItem(theValue, theLabel);
1180
            }
1181
        }
1182
        return r;
1183
    }
1184

    
1185
    private DynObjectValueItem[] getAvailableValuesFromExpression() {
1186
        if (this.availableValuesExpression == null || this.availableValuesExpression.isEmpty()) {
1187
            return null;
1188
        }
1189
        try {
1190
            Object value = this.availableValuesExpression.execute(null);
1191
            if (value instanceof DynObjectValueItem[]) {
1192
                return (DynObjectValueItem[]) value;
1193
            }
1194
            if (value instanceof List) {
1195
                return this.getAvailableValuesFrom(new GetItemWithSize() {
1196
                    @Override
1197
                    public Object get(int i) {
1198
                        return ((List) value).get(i);
1199
                    }
1200

    
1201
                    @Override
1202
                    public int size() {
1203
                        return ((List) value).size();
1204
                    }
1205
                });
1206
            }
1207
        } catch (Throwable th) {
1208
            LOGGER.warn("Can't get available values from expression", th);
1209
        }
1210
        return null;
1211
    }
1212

    
1213
    @Override
1214
    public Expression getAvailableValuesExpression() {
1215
        return this.availableValuesExpression;
1216
    }
1217

    
1218
    @Override
1219
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1220
        if (StringUtils.isBlank(expression)) {
1221
            this.availableValuesExpression = null;
1222
            return this;
1223
        }
1224
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1225
        return this;
1226
    }
1227

    
1228
    @Override
1229
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1230
        this.availableValuesExpression = expression;
1231
        return this;
1232
    }
1233

    
1234
    @Override
1235
    public String getLabelOfValue(Object value) {
1236
        if (this.labelOfValueMap != null) {
1237
            String theLabel = this.labelOfValueMap.get(value);
1238
            if (theLabel == null) {
1239
                theLabel = Objects.toString(value, "");
1240
            }
1241
            return theLabel;
1242
        }
1243
        DynObjectValueItem[] values = this.getAvailableValues();
1244
        if (values == null) {
1245
            return Objects.toString(value, "");
1246
        }
1247
        Map<Object, String> map = new LinkedHashMap<>();
1248
        for (DynObjectValueItem theValue : values) {
1249
            map.put(theValue.getValue(), theValue.getLabel());
1250
        }
1251
        this.labelOfValueMap = map;
1252
        String theLabel = this.labelOfValueMap.get(value);
1253
        if (theLabel == null) {
1254
            theLabel = Objects.toString(value, "");
1255
        }
1256
        return theLabel;
1257
    }
1258

    
1259
    @Override
1260
    public String getDescription() {
1261
        if (this.description == null) {
1262
            return getName();
1263
        }
1264
        return this.description;
1265
    }
1266

    
1267
    @Override
1268
    public Object getMaxValue() {
1269
        return this.maxValue;
1270
    }
1271

    
1272
    @Override
1273
    public Object getMinValue() {
1274
        return this.minValue;
1275
    }
1276

    
1277
    @Override
1278
    public int getTheTypeOfAvailableValues() {
1279
        return 1;
1280
    }
1281

    
1282
    @Override
1283
    public int getType() {
1284
        if (featureAttributeGetter != null) {
1285
            return featureAttributeGetter.getDataType().getType();
1286
        }
1287
        return getDataType().getType();
1288
    }
1289

    
1290
    @Override
1291
    public boolean isMandatory() {
1292
        return !allowNull() || isPrimaryKey();
1293
    }
1294

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

    
1300
    @Override
1301
    public DynField setAvailableValues(DynObjectValueItem[] values) {
1302
        if (ArrayUtils.isEmpty(values)) {
1303
            this.availableValues = null;
1304
        } else {
1305
            this.availableValues = values;
1306
        }
1307
        return this;
1308
    }
1309

    
1310
    @Override
1311
    public DynField setDescription(String description) {
1312
        this.description = description;
1313
        return this;
1314
    }
1315

    
1316
    @Override
1317
    public DynField setMandatory(boolean mandatory) {
1318
        throw new UnsupportedOperationException();
1319
    }
1320

    
1321
    @Override
1322
    public DynField setMaxValue(Object maxValue) {
1323
        try {
1324
            this.maxValue = this.coerce(maxValue);
1325
        } catch (CoercionException e) {
1326
            throw new IllegalArgumentException(e);
1327
        }
1328
        return this;
1329
    }
1330

    
1331
    @Override
1332
    public DynField setMinValue(Object minValue) {
1333
        try {
1334
            this.maxValue = this.coerce(minValue);
1335
        } catch (CoercionException e) {
1336
            throw new IllegalArgumentException(e);
1337
        }
1338
        return this;
1339
    }
1340

    
1341
    @Override
1342
    public DynField setPersistent(boolean persistent) {
1343
        throw new UnsupportedOperationException();
1344
    }
1345

    
1346
    @Override
1347
    public DynField setTheTypeOfAvailableValues(int type) {
1348
        throw new UnsupportedOperationException();
1349
    }
1350

    
1351
    @Override
1352
    public DynField setType(int type) {
1353
        throw new UnsupportedOperationException();
1354
    }
1355

    
1356
    @Override
1357
    @Deprecated
1358
    public DynField setDefaultDynValue(Object defaultValue) {
1359
        return this.setDefaultFieldValue(defaultValue);
1360
    }
1361

    
1362
    @Override
1363
    public DynField setDefaultFieldValue(Object defaultValue) {
1364
        this.defaultValue = defaultValue;
1365
        return this;
1366
    }
1367

    
1368
    @Override
1369
    public Class getClassOfValue() {
1370
        return null;
1371
    }
1372

    
1373
    @Override
1374
    public DynField getElementsType() {
1375
        return null;
1376
    }
1377

    
1378
    @Override
1379
    public DynField setClassOfValue(Class theClass)
1380
            throws DynFieldIsNotAContainerException {
1381
        throw new UnsupportedOperationException();
1382
    }
1383

    
1384
    @Override
1385
    public DynField setElementsType(DynStruct type)
1386
            throws DynFieldIsNotAContainerException {
1387
        throw new UnsupportedOperationException();
1388
    }
1389

    
1390
    @Override
1391
    public DynField setElementsType(int type)
1392
            throws DynFieldIsNotAContainerException {
1393
        throw new UnsupportedOperationException();
1394
    }
1395

    
1396
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1397
        this.dataProfile = dataProfile;
1398
        return this;
1399
    }
1400

    
1401
    @Override
1402
    public String getDataProfileName() {
1403
        return dataProfile;
1404
    }
1405

    
1406
    @Override
1407
    public DataProfile getDataProfile() {
1408
        if (StringUtils.isBlank(dataProfile)) {
1409
            return null;
1410
        }
1411
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1412
        return profile;
1413
    }
1414

    
1415
    @Override
1416
    public void validate(Object value) throws DynFieldValidateException {
1417

    
1418
        if (value == null && !this.allowNull()) {
1419
            throw new DynFieldValidateException(value, this, null);
1420
        }
1421

    
1422
        try {
1423
            this.dataType.coerce(value);
1424
        } catch (CoercionException e) {
1425
            throw new DynFieldValidateException(value, this, e);
1426
        }
1427

    
1428
        /*
1429
         * Other checks will be needed
1430
         */
1431
    }
1432

    
1433
    @Override
1434
    public String getSubtype() {
1435
        if (featureAttributeGetter != null) {
1436
            return featureAttributeGetter.getDataType().getSubtype();
1437
        }
1438
        return this.dataType.getSubtype();
1439
    }
1440

    
1441
    @Override
1442
    public Object coerce(Object value) throws CoercionException {
1443
        if (value == null) {
1444
            return value; // O debe devolver this.defaultValue
1445
        }
1446
        try {
1447
            return this.getDataType().coerce(value, this.getCoercionContext());
1448
        } catch (Exception ex) {
1449
            throw new RuntimeException(ex);
1450
        }
1451
    }
1452

    
1453
    @Override
1454
    public DynField setAvailableValues(List values) {
1455
        if (values == null || values.isEmpty()) {
1456
            this.availableValues = null;
1457
        } else {
1458
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1459
                    new DynObjectValueItem[values.size()]
1460
            );
1461
        }
1462
        return this;
1463
    }
1464

    
1465
    @Override
1466
    public String getGroup() {
1467
        return this.groupName;
1468
    }
1469

    
1470
    @Override
1471
    public int getOder() {
1472
        return this.order;
1473
    }
1474

    
1475
    @Override
1476
    public String getLabel() {
1477
        if (this.label == null) {
1478
            return this.getName();
1479
        }
1480
        return this.label;
1481
    }
1482

    
1483
    @Override
1484
    public String getLocalizedLabel() {
1485
        if (StringUtils.isBlank(this.label)) {
1486
            return this.getName();
1487
        }
1488
        I18nManager i18n = ToolsLocator.getI18nManager();
1489
        return i18n.getTranslation(this.label);
1490
    }
1491

    
1492
    @Override
1493
    public DynField setLabel(String label) {
1494
        this.label = label;
1495
        return this;
1496
    }
1497

    
1498
    @Override
1499
    public DynField setShortLabel(String shortLabel) {
1500
        this.shortLabel = shortLabel;
1501
        return this;
1502
    }
1503

    
1504
    @Override
1505
    public String getShortLabel() {
1506
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1507
    }
1508

    
1509
    @Override
1510
    public String getLocalizedShortLabel() {
1511
        if (StringUtils.isBlank(shortLabel)) {
1512
            return this.getLocalizedLabel();
1513
        }
1514
        I18nManager i18n = ToolsLocator.getI18nManager();
1515
        return i18n.getTranslation(shortLabel);
1516
    }
1517

    
1518
    @Override
1519
    public DynField setGroup(String groupName) {
1520
        this.groupName = groupName;
1521
        return this;
1522
    }
1523

    
1524
    @Override
1525
    public DynField setOrder(int order) {
1526
        this.order = order;
1527
        return this;
1528
    }
1529

    
1530
    @Override
1531
    public DynField setHidden(boolean hidden) {
1532
        this.hidden = hidden;
1533
        return this;
1534
    }
1535

    
1536
    @Override
1537
    public boolean isHidden() {
1538
        return this.hidden;
1539
    }
1540

    
1541
    @Override
1542
    public DynField setReadOnly(boolean readOnly) {
1543
        this.readOnly = readOnly;
1544
        return this;
1545
    }
1546

    
1547
    @Override
1548
    public boolean isContainer() {
1549
        return false;
1550
    }
1551

    
1552
    @Override
1553
    public Class getClassOfItems() {
1554
        return null;
1555
    }
1556

    
1557
    @Override
1558
    public DynField setClassOfItems(Class theClass) {
1559
        throw new UnsupportedOperationException();
1560
    }
1561

    
1562
    @Override
1563
    public DynField setType(DataType type) {
1564
        throw new UnsupportedOperationException();
1565
    }
1566

    
1567
    @Override
1568
    public DynField setSubtype(String subtype) {
1569
        throw new UnsupportedOperationException();
1570
    }
1571

    
1572
    @Override
1573
    public boolean isTime() {
1574
        return isTime;
1575
    }
1576

    
1577
    @Override
1578
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1579
        return featureAttributeGetter;
1580
    }
1581

    
1582
    @Override
1583
    public void setFeatureAttributeGetter(
1584
            FeatureAttributeGetter featureAttributeTransform) {
1585
        this.featureAttributeGetter = featureAttributeTransform;
1586
    }
1587

    
1588
    @Override
1589
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1590
        return this.featureAttributeEmulator;
1591
    }
1592

    
1593
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1594
        this.featureAttributeEmulator = featureAttributeEmulator;
1595
        return this;
1596
    }
1597

    
1598
    @Override
1599
    public boolean isIndexed() {
1600
        return this.indexed;
1601
    }
1602

    
1603
    @Override
1604
    public boolean isForeingKey() {
1605
        return this.foreingKey != null && this.foreingKey.isForeingKey();
1606
    }
1607

    
1608
    @Override
1609
    public ForeingKey getForeingKey() {
1610
        return this.foreingKey;
1611
    }
1612

    
1613
    @Override
1614
    public boolean allowIndexDuplicateds() {
1615
        return this.allowIndexDuplicateds;
1616
    }
1617

    
1618
    @Override
1619
    public boolean isIndexAscending() {
1620
        return this.isIndexAscending;
1621
    }
1622

    
1623
    @Override
1624
    public DynField setClassOfValue(DynStruct dynStrct) {
1625
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1626
    }
1627

    
1628
    @Override
1629
    public DynField setClassOfValue(String theClassNameOfValue) {
1630
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1631
    }
1632

    
1633
    @Override
1634
    public String getClassNameOfValue() {
1635
        return null;
1636
    }
1637

    
1638
    @Override
1639
    public DynStruct getDynClassOfValue() {
1640
        return null;
1641
    }
1642

    
1643
    @Override
1644
    public DynField setTypeOfItems(int type) {
1645
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1646
    }
1647

    
1648
    @Override
1649
    public int getTypeOfItems() {
1650
        return DataTypes.INVALID;
1651
    }
1652

    
1653
    @Override
1654
    public DynField setClassOfItems(DynStruct dynStrct) {
1655
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1656
    }
1657

    
1658
    @Override
1659
    public DynField setClassOfItems(String theClassNameOfValue) {
1660
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1661
    }
1662

    
1663
    @Override
1664
    public String getClassNameOfItems() {
1665
        return null;
1666
    }
1667

    
1668
    @Override
1669
    public DynStruct getDynClassOfItems() {
1670
        return null;
1671
    }
1672

    
1673
    @Override
1674
    public DynField setRelationType(int relationType) {
1675
        this.relationType = relationType;
1676
        return this;
1677
    }
1678

    
1679
    @Override
1680
    public int getRelationType() {
1681
        return this.relationType;
1682
    }
1683

    
1684
    @Override
1685
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1686
        this.availableValuesMethod = availableValuesMethod;
1687
        return this;
1688
    }
1689

    
1690
    @Override
1691
    public DynMethod getAvailableValuesMethod() {
1692
        if (this.availableValuesMethod != null) {
1693
            return this.availableValuesMethod;
1694
        }
1695
        if (this.availableValuesFilter == null && !this.isForeingKey()) {
1696
            return null;
1697
        }
1698
        DynMethod method = new AbstractDynMethod("getAvailableValuesOf" + this.getName()) {
1699
            @Override
1700
            public Object invoke(DynObject context, Object[] args) throws DynMethodException {
1701
                return getAvailableValues(context);
1702
            }
1703
        };
1704
        return method;
1705
    }
1706

    
1707
    @Override
1708
    public DynMethod getCalculateMethod() {
1709
        return this.calculateMethod;
1710
    }
1711

    
1712
    @Override
1713
    public DynField setCalculateMethod(DynMethod method) {
1714
        this.calculateMethod = method;
1715
        return this;
1716
    }
1717

    
1718
    @Override
1719
    public boolean isCalculated() {
1720
        return this.calculateMethod != null;
1721
    }
1722

    
1723
    @Override
1724
    public Object getCalculatedValue(DynObject self) {
1725
        try {
1726
            return this.calculateMethod.invoke(self, new Object[]{this});
1727
        } catch (DynMethodException ex) {
1728
            throw new RuntimeException(ex);
1729
        }
1730
    }
1731

    
1732
    @Override
1733
    public DynField setValidateElements(boolean validate) {
1734
        return this;
1735
    }
1736

    
1737
    @Override
1738
    public boolean getValidateElements() {
1739
        return false;
1740
    }
1741

    
1742
    @Override
1743
    public boolean hasLabel() {
1744
        return StringUtils.isNotBlank(this.label);
1745
    }
1746

    
1747
    @Override
1748
    public boolean hasShortLabel() {
1749
        return StringUtils.isNotBlank(this.shortLabel);
1750
    }
1751

    
1752
    @Override
1753
    public boolean hasDescription() {
1754
        return StringUtils.isNotBlank(this.description);
1755
    }
1756

    
1757
    @Override
1758
    public FeatureAttributeDescriptor getValue() {
1759
        return this;
1760
    }
1761

    
1762
    @Override
1763
    public int getDisplaySize() {
1764
        return this.displaySize;
1765
    }
1766

    
1767
    @Override
1768
    public boolean isInAvailableValues(Object valueToCheck) {
1769
        if (this.getAvailableValues() != null) {
1770
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1771
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1772
                    return true;
1773
                }
1774
            }
1775
        }
1776
        return false;
1777
    }
1778

    
1779
    private class ConstantValueEvaluator extends AbstractEvaluator {
1780

    
1781
        @Override
1782
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1783
            return defaultValue;
1784
        }
1785

    
1786
        @Override
1787
        public String getName() {
1788
            return "Constant attribute " + name;
1789
        }
1790
    }
1791

    
1792
    public void setConstantValue(boolean isConstantValue) {
1793
        if (isConstantValue) {
1794
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1795
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1796
             * el evaluador el que se encarga de proporcionar su valor.
1797
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1798
             * por defecto para ese attributo.
1799
             */
1800
            this.evaluator = new ConstantValueEvaluator();
1801
        } else {
1802
            this.evaluator = null;
1803
        }
1804
    }
1805

    
1806
    @Override
1807
    public boolean isComputed() {
1808
        return featureAttributeEmulator != null || evaluator != null || isCalculated();
1809
    }
1810

    
1811
    @Override
1812
    public FeatureStore getStore() {
1813
        FeatureType ftype = this.getFeatureType();
1814
        if (ftype == null) {
1815
            return null;
1816
        }
1817
        return ftype.getStore();
1818
    }
1819

    
1820
    @Override
1821
    public FeatureType getFeatureType() {
1822
        if (this.typeRef == null) {
1823
            return null;
1824
        }
1825
        FeatureType ftype = (FeatureType) this.typeRef.get();
1826
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1827
        return ftype;
1828
    }
1829

    
1830
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1831
        this.interval = interval;
1832
        return this;
1833
    }
1834

    
1835
    public void fixAll() {
1836
        if (!this.getDataType().supportSize()) {
1837
            this.size = 0;
1838
        }
1839
        NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1840
        this.precision = ps.getPrecision();
1841
        this.scale = ps.getScale();
1842

    
1843
        switch (this.getType()) {
1844
            case DataTypes.INSTANT:
1845
            case DataTypes.INTERVAL:
1846
            case DataTypes.DATE:
1847
            case DataTypes.TIME:
1848
            case DataTypes.TIMESTAMP:
1849
                if (this.getInterval() != null) {
1850
                    this.isTime = true;
1851
                }
1852
                break;
1853
        }
1854
    }
1855

    
1856
    @Override
1857
    public String[] getRequiredFieldNames() {
1858
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1859
        if (emulator == null) {
1860
            return null;
1861
        }
1862
        return emulator.getRequiredFieldNames();
1863
    }
1864

    
1865
    @Override
1866
    public void recentUsed() {
1867
        DefaultFeatureType.RECENTS_USEDS.add(this);
1868
    }
1869

    
1870
    @Override
1871
    public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1872
        if (other == null) {
1873
            throw new NullPointerException();
1874
        }
1875
        DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1876
        if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1877
            return false;
1878
        }
1879
        if (old.isComputed() && old.isComputed() == this.isComputed()) {
1880
            return true;
1881
        }
1882
        if (this.dataType != old.dataType) {
1883
            return false;
1884
        }
1885
        if (this.size != old.size) {
1886
            return false;
1887
        }
1888
        if (this.precision != old.precision) {
1889
            return false;
1890
        }
1891
//        if( this.primaryKey != old.primaryKey ) {
1892
//            return false;
1893
//        }
1894
        if (this.geomType != old.geomType) {
1895
            return false;
1896
        }
1897
        if (this.SRS != old.SRS) {
1898
            return false;
1899
        }
1900
        if (this.isAutomatic != old.isAutomatic) {
1901
            return false;
1902
        }
1903
        return true;
1904
    }
1905

    
1906
    private class PropertiesBuilder {
1907

    
1908
        private String name;
1909
        private DataType type;
1910
        private Map<String, String> sets;
1911
        private String sep;
1912

    
1913
        public PropertiesBuilder() {
1914
            this.sets = new LinkedHashMap<>();
1915
        }
1916

    
1917
        public void separator(String sep) {
1918
            this.sep = sep;
1919
        }
1920

    
1921
        public void name(String name) {
1922
            this.name = name;
1923
        }
1924

    
1925
        public void type(DataType type) {
1926
            this.type = type;
1927
        }
1928

    
1929
        public void set(String name, ForeingKey fk) {
1930
            if (fk == null) {
1931
                return;
1932
            }
1933
            if (!fk.isForeingKey()) {
1934
                return;
1935
            }
1936
            this.set(name, fk.isForeingKey());
1937
            this.set(name + "_code", fk.getCodeName());
1938
            this.set(name + "_label", fk.getLabelFormula());
1939
            this.set(name + "_closedlist", fk.isClosedList());
1940
            this.set(name + "_table", fk.getTableName());
1941
        }
1942

    
1943
        public void set(String name, FeatureAttributeEmulator value) {
1944
            if (value == null) {
1945
                return;
1946
            }
1947
            if (value instanceof FeatureAttributeEmulatorExpression) {
1948
                this.set(name, ((FeatureAttributeEmulatorExpression) value).getExpression().getPhrase());
1949
            }
1950
        }
1951

    
1952
        public void set(String name, IProjection value) {
1953
            if (value == null) {
1954
                return;
1955
            }
1956
            this.set(name, value.getAbrev());
1957
        }
1958

    
1959
        public void set(String name, GeometryType value) {
1960
            if (value == null) {
1961
                return;
1962
            }
1963
            this.set(name, value.getFullName().replace(":", "@"));
1964
        }
1965

    
1966
        public void set(String name, Object value) {
1967
            if (value == null) {
1968
                return;
1969
            }
1970
            String s = Objects.toString(value, "");
1971
            if (StringUtils.isBlank(s)) {
1972
                return;
1973
            }
1974
            this.sets.put(name, s);
1975
        }
1976

    
1977
        public void set(String name, Object value, Object skipValue) {
1978
            if (value == null || value == skipValue) {
1979
                return;
1980
            }
1981
            String s = Objects.toString(value, "");
1982
            if (StringUtils.isBlank(s)) {
1983
                return;
1984
            }
1985
            this.sets.put(name, s);
1986
        }
1987

    
1988
        @Override
1989
        public String toString() {
1990
            StringBuilder builder = new StringBuilder();
1991
            builder.append(this.name);
1992
            builder.append(sep);
1993
            builder.append(this.type.getName());
1994
            for (String key : this.sets.keySet()) {
1995
                builder.append(sep);
1996
                builder.append("set");
1997
                builder.append(sep);
1998
                builder.append(key);
1999
                builder.append("=");
2000
                builder.append(this.sets.get(key));
2001
            }
2002
            return builder.toString();
2003
        }
2004
    }
2005

    
2006
    private String getAll() {
2007
        PropertiesBuilder builder = new PropertiesBuilder();
2008
        builder.separator("/");
2009
        builder.name(this.name);
2010
        builder.type(this.dataType);
2011
        builder.set("size", this.size, 0);
2012
        switch (this.getType()) {
2013
            case DataTypes.BYTE:
2014
            case DataTypes.INTEGER:
2015
            case DataTypes.LONG:
2016
                break;
2017
            case DataTypes.FLOAT:
2018
            case DataTypes.DOUBLE:
2019
                builder.set("locale", this.getLocale());
2020
                break;
2021
            case DataTypes.DECIMAL:
2022
                builder.set("precision", this.precision);
2023
                builder.set("scale", this.scale);
2024
                builder.set("roundMode", this.getRoundMode());
2025
                builder.set("locale", this.getLocale());
2026
                break;
2027
            case DataTypes.DATE:
2028
            case DataTypes.TIME:
2029
            case DataTypes.TIMESTAMP:
2030
                builder.set("locale", this.getLocale());
2031
                break;
2032
            case DataTypes.GEOMETRY:
2033
                IProjection proj = this.getSRS();
2034
                if (proj != null) {
2035
                    builder.set("srs", proj.getAbrev().replace(":", "@"));
2036
                }
2037
                GeometryType theGeomType = this.getGeomType();
2038
                if (theGeomType != null) {
2039
                    String geomTypeName = GeometryUtils.getGeometryTypeName(this.getGeomType().getType());
2040
                    String geomSubtypeName = GeometryUtils.getGeometrySubtypeName(this.getGeomType().getSubType());
2041
                    builder.set("geomtype", geomTypeName + "@" + geomSubtypeName);
2042
                }
2043
                break;
2044
        }
2045
        builder.set("hidden", this.isHidden(), false);
2046
        builder.set("readOnly", this.isReadOnly(), false);
2047
        builder.set("allowNull", this.allowNull(), true);
2048
        builder.set("pk", this.isPrimaryKey(), false);
2049
        builder.set("automatic", this.isAutomatic(), false);
2050
        builder.set("isTime", this.isTime(), false);
2051
        builder.set("profile", this.getDataProfileName());
2052
        builder.set("group", this.getGroup());
2053
        builder.set("description", this.description);
2054
        builder.set("label", this.label);
2055
        builder.set("shortLabel", this.shortLabel);
2056
        builder.set("order", this.getOder());
2057
        if (this.getFeatureAttributeEmulator() instanceof FeatureAttributeEmulatorExpression) {
2058
            Expression exp = ((FeatureAttributeEmulatorExpression) this.getFeatureAttributeEmulator()).getExpression();
2059
            if (exp != null) {
2060
                builder.set("expression", exp.getPhrase());
2061
            }
2062
        }
2063
        builder.set("isAvoidCachingAvailableValues", this.isAvoidCachingAvailableValues(), false);
2064
        if (this.isForeingKey()) {
2065
            builder.set("fk", this.isForeingKey());
2066
            builder.set("fk_table", this.getForeingKey().getTableName());
2067
            builder.set("fk_code", this.getForeingKey().getCodeName());
2068
            builder.set("fk_label", this.getForeingKey().getLabelFormula());
2069
            builder.set("fk.closedlist", this.getForeingKey().isClosedList());
2070
        }
2071
        return builder.toString();
2072
    }
2073

    
2074
    @Override
2075
    public Object get(String name) {
2076
        if (StringUtils.isBlank(name)) {
2077
            throw new IllegalArgumentException("Name can't be empty");
2078
        }
2079
        switch (name.trim().toLowerCase()) {
2080
            case "all":
2081
                return this.getAll();
2082
            case "isreadonly":
2083
            case "readonly":
2084
                return this.isReadOnly();
2085
            case "hidden":
2086
                return this.isHidden();
2087
            case "allownull":
2088
                return this.allowNull();
2089
            case "pk":
2090
            case "ispk":
2091
            case "primarykey":
2092
            case "isprimarykey":
2093
                return this.isPrimaryKey();
2094
            case "isautomatic":
2095
            case "automatic":
2096
                return this.isAutomatic();
2097
            case "time":
2098
            case "istime":
2099
                return this.isTime();
2100
            case "profile":
2101
                return this.getDataProfile();
2102
            case "group":
2103
                return this.getGroup();
2104
            case "description":
2105
                return this.getDescription();
2106
            case "label":
2107
                return this.getLabel();
2108
            case "shortlabel":
2109
                return this.getShortLabel();
2110
            case "isavoidcachingavailablevalues":
2111
            case "avoidcachingavailablevalues":
2112
            case "nocachingavailablevalues":
2113
                return this.isAvoidCachingAvailableValues();
2114
            case "expression":
2115
                return this.getFeatureAttributeEmulator();
2116
            case "size":
2117
                return this.getSize();
2118
            case "precision":
2119
                return this.getPrecision();
2120
            case "scale":
2121
                return this.getScale();
2122
            case "roundmode":
2123
                return this.getRoundMode();
2124
            case "locale":
2125
                return this.getLocale();
2126
            case "order":
2127
                return this.getOder();
2128
            case "isfk":
2129
            case "isforeingkey":
2130
                return this.isForeingKey();
2131
            case "fk":
2132
            case "foreingkey":
2133
                return this.getForeingKey();
2134
            case "fk_code":
2135
            case "foreingkey_code":
2136
            case "foreingkey.code":
2137
                return this.getForeingKey().getCodeName();
2138
            case "fk_label":
2139
            case "foreingkey_label":
2140
            case "foreingkey.label":
2141
                return this.getForeingKey().getLabelFormula();
2142
            case "fk.closedlist":
2143
            case "foreingkey_closedlist":
2144
            case "foreingkey.closedlist":
2145
                return this.getForeingKey().isClosedList();
2146
            case "fk_table":
2147
            case "foreingkey_table":
2148
            case "foreingkey.table":
2149
                return this.getForeingKey().getTableName();
2150
            case "interval":
2151
                return this.getInterval();
2152
            case "geomtype":
2153
            case "geometrytype":
2154
                return this.getGeomType();
2155
            case "srs":
2156
                return this.getSRS();
2157
            default:
2158
                throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
2159
        }
2160
    }
2161

    
2162
    public void setSRSForced(IProjection SRS) {
2163
        this.SRS = SRS;
2164
    }
2165

    
2166
    @Override
2167
    public JsonObject toJson() {
2168
        return this.toJsonBuilder().build();
2169
    }
2170

    
2171
    @Override
2172
    public JsonObjectBuilder toJsonBuilder() {
2173
        JsonObjectBuilder builder = Json.createObjectBuilder();
2174
        builder.add_class(this);
2175
        builder.add("name", this.name);
2176
        builder.add("description", this.description);
2177
        builder.add("label", this.label);
2178
        builder.add("shortLabel", this.shortLabel);
2179
        builder.add("order", this.order);
2180
        builder.add("groupName", this.groupName);
2181
        builder.add("dataType", this.dataType);
2182
        builder.add("size", this.size);
2183
        builder.add("precision", this.precision);
2184
        builder.add("scale", this.scale);
2185
        builder.add("roundMode", this.roundMode);
2186

    
2187
        builder.add("allowNull", this.allowNull);
2188
        builder.add("primaryKey", this.primaryKey);
2189
        builder.add("readOnly", this.readOnly);
2190
        builder.add("isAutomatic", this.isAutomatic);
2191
        builder.add("isTime", this.isTime);
2192
        builder.add("indexed", this.indexed);
2193
        builder.add("isIndexAscending", this.isIndexAscending);
2194
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2195
        builder.add("hidden", this.hidden);
2196
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2197

    
2198
        builder.add("geometryType", this.getGeomType());
2199
        builder.add("srs", this.getSRS());
2200

    
2201
        builder.add("relationType", this.relationType);
2202
        builder.add("displaySize", this.displaySize);
2203
        builder.add("locale", this.getLocale());
2204
        builder.add("expression", this.getFeatureAttributeEmulator());
2205
        if (this.isForeingKey()) {
2206
            builder.add("fk", this.isForeingKey());
2207
            builder.add("fk_table", this.getForeingKey().getTableName());
2208
            builder.add("fk_code", this.getForeingKey().getCodeName());
2209
            builder.add("fk_label", this.getForeingKey().getLabelFormula());
2210
            builder.add("fk_closedlist", this.getForeingKey().isClosedList());
2211
        }
2212
        builder.add("availableValuesExpression", this.availableValuesExpression);
2213
        builder.add("defaultValue", Objects.toString(this.defaultValue, null));
2214
        builder.add("dataProfile", this.getDataProfileName());
2215
        builder.add("tags", tags);
2216
        builder.add("availableValues", availableValues);
2217
        builder.add("additionalInfo", this.additionalInfo);
2218
        return builder;
2219
    }
2220

    
2221
    public void fromJson(JsonObject json) {
2222
        this.name = json.getString("name");
2223
        this.description = json.getString("description");
2224
        this.label = json.getString("label");
2225
        this.shortLabel = json.getString("shortLabel");
2226
        this.order = json.getInt("order");
2227
        this.groupName = json.getString("groupName");
2228
        this.precision = json.getInt("precision");
2229
        this.size = json.getInt("size");
2230
        this.scale = json.getInt("scale");
2231
        this.roundMode = json.getInt("roundMode");
2232

    
2233
        this.allowNull = json.getBoolean("allowNull");
2234
        this.primaryKey = json.getBoolean("primaryKey");
2235
        this.readOnly = json.getBoolean("readOnly");
2236
        this.isAutomatic = json.getBoolean("isAutomatic");
2237
        this.isTime = json.getBoolean("isTime");
2238
        this.indexed = json.getBoolean("indexed");
2239
        this.isIndexAscending = json.getBoolean("isIndexAscending");
2240
        this.allowIndexDuplicateds = json.getBoolean("allowIndexDuplicateds");
2241
        this.hidden = json.getBoolean("hidden");
2242
        this.avoidCachingAvailableValues = json.getBoolean("avoidCachingAvailableValues");
2243

    
2244
        this.relationType = json.getInt("relationType");
2245
        this.displaySize = json.getInt("displaySize");
2246

    
2247
        this.dataType = (DataType) Json.toObject(json, "dataType");
2248
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2249
        this.SRS = (IProjection) Json.toObject(json, "srs");
2250
        this.locale = (Locale) Json.toObject(json, "locale");
2251
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json, "expression");
2252

    
2253
        this.tags = (Tags) Json.toObject(json, "tags");
2254
        this.additionalInfo = Json.toMap(json, "additionalInfo");
2255
        this.availableValues = (DynObjectValueItem[]) Json.toArray(json, "availableValues", new DynObjectValueItem[0]);
2256
        this.dataProfile = json.getString("dataProfile", null);
2257
        try {
2258
            this.defaultValue = json.getString("defaultValue", null);
2259
            if(!(this.defaultValue instanceof String && ExpressionUtils.isDynamicText((String) this.defaultValue))){
2260
                this.defaultValue = this.coerce(this.defaultValue);
2261
            }
2262
        } catch (Exception ex) {
2263
            LOGGER.warn("Can't retrive default value for attribute '" + this.name + "'.", ex);
2264
        }
2265
        this.availableValuesExpression = (Expression) Json.toObject(json, "availableValuesExpression");
2266
        if (json.getBoolean("fk", false)) {
2267
            this.foreingKey = new DefaultForeingKey();
2268
            this.foreingKey.setForeingKey(true);
2269
            this.foreingKey.setTableName(json.getString("fk_table", null));
2270
            this.foreingKey.setCodeName(json.getString("fk_code", null));
2271
            this.foreingKey.setLabelFormula(json.getString("fk_label", null));
2272
            this.foreingKey.setClosedList(json.getBoolean("fk_closedlist", false));
2273
        } else {
2274
            this.foreingKey = null;
2275
        }
2276
    }
2277

    
2278
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2279

    
2280
        public TheJsonSerializer() {
2281
        }
2282

    
2283
        @Override
2284
        public Class getObjectClass() {
2285
            return DefaultFeatureAttributeDescriptor.class;
2286
        }
2287

    
2288
        @Override
2289
        public Object toObject(JsonObject json) {
2290
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2291
            o.fromJson(json);
2292
            return o;
2293
        }
2294

    
2295
        @Override
2296
        public JsonObjectBuilder toJsonBuilder(Object value) {
2297
            return ((SupportToJson) value).toJsonBuilder();
2298
        }
2299

    
2300
    }
2301

    
2302
    public static void selfRegister() {
2303
        Json.registerSerializer(new TheJsonSerializer());
2304
    }
2305

    
2306
}