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

History | View | Annotate | Download (77.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
    protected String defaultFormat;
171

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

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

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

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

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

    
292
        // TODO: ? Habria que clonarlos ?
293
        this.availableValuesMethod = other.availableValuesMethod;
294
        this.calculateMethod = other.calculateMethod;
295
        this.relationType = other.relationType;
296
        this.locale = other.locale;
297
        this.displaySize = other.displaySize;
298
        this.avoidCachingAvailableValues = other.avoidCachingAvailableValues;
299
    }
300

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

    
311
    @Override
312
    public String getDataTypeName() {
313
        if (this.getDataType() == null) {
314
            return "(unknow)";
315
        }
316
        return this.getDataType().getName();
317
    }
318

    
319
    @Override
320
    public DefaultFeatureAttributeDescriptor getCopy() {
321
        return new DefaultFeatureAttributeDescriptor(this);
322
    }
323

    
324
    @Override
325
    public Object clone() throws CloneNotSupportedException {
326
        return new DefaultFeatureAttributeDescriptor(this);
327
    }
328

    
329
    @Override
330
    public boolean allowNull() {
331
        return allowNull;
332
    }
333

    
334
    @Override
335
    public Locale getLocale() {
336
        if (this.locale == null) {
337
            if (this.dataType.isNumeric()) {
338
                this.locale = Locale.ENGLISH; //return
339
            } else {
340
                this.locale = Locale.getDefault();
341
            }
342
        }
343
        return this.locale;
344
    }
345

    
346
    @Override
347
    public DataType getDataType() {
348
        if (featureAttributeGetter != null) {
349
            return featureAttributeGetter.getDataType();
350
        }
351
        return this.dataType;
352
    }
353

    
354
    public FeatureAttributeDescriptor setDataType(int type) {
355
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
356
        return this;
357
    }
358

    
359
    @Override
360
    public DateFormat getDateFormat() {
361
        return this.dateFormat;
362
    }
363

    
364
    @Override
365
    public Object getDefaultValue() {
366
        return this.defaultValue;
367
    }
368

    
369
    @Override
370
    @Deprecated
371
    public Object getDefaultValueCoerced() {
372
        return getCoercedDefaultValue();
373
    }
374

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

    
391
    @Override
392
    public Supplier getDefaultValueSupplier() {
393
        return (Supplier) this::getDefaultValueCoerced;
394
    }
395

    
396
    @Override
397
    public DynField setDefaultValueSupplier(Supplier supplier) {
398
        //Do nothing
399
        return this;
400
    }
401

    
402
    @Override
403
    public Evaluator getEvaluator() {
404
        return this.evaluator;
405
    }
406

    
407
    @Override
408
    public int getGeometryType() {
409
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
410
            return Geometry.TYPES.UNKNOWN;
411
        }
412
        return this.geometryType;
413
    }
414

    
415
    @Override
416
    public int getGeometrySubType() {
417
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
418
            return Geometry.SUBTYPES.UNKNOWN;
419
        }
420
        return this.geometrySubType;
421
    }
422

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

    
443
    @Override
444
    public int getIndex() {
445
        return this.index;
446
    }
447

    
448
    protected FeatureAttributeDescriptor setIndex(int index) {
449
        this.index = index;
450
        return this;
451
    }
452

    
453
    @Override
454
    public int getMaximumOccurrences() {
455
        return this.maximumOccurrences;
456
    }
457

    
458
    @Override
459
    public int getMinimumOccurrences() {
460
        return this.minimumOccurrences;
461
    }
462

    
463
    @Override
464
    public String getName() {
465
        return this.name;
466
    }
467

    
468
    public FeatureAttributeDescriptor setName(String name) {
469
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
470
        this.name = name;
471
        return this;
472
    }
473

    
474
    @Override
475
    public Class getObjectClass() {
476
        if (getDataType().getType() == DataTypes.OBJECT) {
477
            return objectClass;
478
        }
479
        return getDataType().getDefaultClass();
480
    }
481

    
482
    @Override
483
    public int getPrecision() {
484
        return this.precision;
485
    }
486

    
487
    @Override
488
    public int getScale() {
489
        return this.scale;
490
    }
491

    
492
    @Override
493
    public Coercion getCoercion() {
494
        return this.getDataType().getCoercion();
495
    }
496

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

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

    
536
    @Override
537
    public int getRoundMode() {
538
        return this.roundMode;
539
    }
540

    
541
    @Override
542
    public IProjection getSRS() {
543
        return this.SRS;
544
    }
545

    
546
    @Override
547
    public Interval getInterval() {
548
        return this.interval;
549
    }
550

    
551
    public IProjection getSRS(WeakReference storeRef) {
552
        if (this.SRS == null) {
553
            FeatureStore store = (FeatureStore) storeRef.get();
554
            this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
555
        }
556
        return this.SRS;
557
    }
558

    
559
    @Override
560
    public int getSize() {
561
        return this.size;
562
    }
563

    
564
    @Override
565
    public boolean isPrimaryKey() {
566
        return this.primaryKey;
567
    }
568

    
569
    @Override
570
    public boolean isReadOnly() {
571
        if (this.readOnly) {
572
            return true;
573
        }
574
        return this.isComputed();
575
    }
576

    
577
    @Override
578
    public String getAdditionalInfo(String infoName) {
579
        if (this.additionalInfo == null) {
580
            return null;
581
        }
582
        return this.additionalInfo.get(infoName);
583
    }
584

    
585
    @Override
586
    public boolean isAutomatic() {
587
        return this.isAutomatic;
588
    }
589

    
590
    @Override
591
    public boolean equals(Object obj) {
592
        if (this == obj) {
593
            return true;
594
        }
595
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
596
            return false;
597
        }
598
        DefaultFeatureAttributeDescriptor other
599
                = (DefaultFeatureAttributeDescriptor) obj;
600

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

    
605
        if (this.index != other.index) {
606
            return false;
607
        }
608

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

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

    
617
        if (this.size != other.size) {
618
            return false;
619
        }
620

    
621
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
622
            return false;
623
        }
624
        if (!Objects.equals(this.defaultFormat, other.defaultFormat)) {
625
            return false;
626
        }
627

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

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

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

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

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

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

    
652
        if (this.geometryType != other.geometryType) {
653
            return false;
654
        }
655

    
656
        if (this.geometrySubType != other.geometrySubType) {
657
            return false;
658
        }
659

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

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

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

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

    
676
        if (!Objects.equals(this.objectClass, other.objectClass)) {
677
            return false;
678
        }
679

    
680
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
681
            return false;
682
        }
683

    
684
        return true;
685
    }
686

    
687
    @Override
688
    public void loadFromState(PersistentState state)
689
            throws PersistenceException {
690
        allowNull = state.getBoolean("allowNull");
691
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
692
        dataProfile = state.getString("dataProfile");
693

    
694
//        FIXME: dateFormat;
695
        try {
696
            defaultValue = dataType.coerce(state.get("defaultValue"));
697
        } catch (CoercionException ex) {
698
        }
699

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

    
746
        Map<String, Object> values = state.getMap("availableValues");
747
        if (values == null || values.isEmpty()) {
748
            this.availableValues = null;
749
        } else {
750
            this.availableValues = new DynObjectValueItem[values.size()];
751
            int n = 0;
752
            Coercion coercion = this.getCoercion();
753
            for (Entry<String, Object> entry : values.entrySet()) {
754
                Object value;
755
                try {
756
                    value = coercion.coerce(entry.getValue());
757
                } catch (CoercionException ex) {
758
                    value = entry.getValue();
759
                }
760
                this.availableValues[n++] = new DynObjectValueItem(value, entry.getKey());
761
            }
762
        }
763

    
764
        description = state.getString("description");
765
        minValue = state.get("minValue");
766
        maxValue = state.get("maxValue");
767
        label = state.getString("label");
768
        order = state.getInt("order");
769
        hidden = state.getBoolean("hidden");
770
        groupName = state.getString("groupName");
771
        relationType = state.getInt("relationType", RELATION_TYPE_NONE);
772

    
773
        foreingKey = (DefaultForeingKey) state.get("foreingKey");
774
        if (foreingKey != null) {
775
            this.foreingKey.setDescriptor(this);
776
        }
777
        tags = (Tags) state.get("tags");
778
        if (tags == null) {
779
            this.tags = new DefaultTags();
780
        }
781
        displaySize = state.getInt("displaySize", 0);
782
        availableValuesExpression = (Expression) state.get("availableValuesExpression");
783
        avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues", false);
784
        availableValuesCache = null;
785
        defaultFormat = state.getString("defaultFormat");
786
    }
787

    
788
    @Override
789
    public void saveToState(PersistentState state) throws PersistenceException {
790
        Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
791

    
792
        state.set("allowNull", allowNull);
793
        state.set("dataType", dataType.getType());
794
        state.set("dataProfile", dataProfile);
795

    
796
//        FIXME: dateFormat;
797
        state.set("defaultValue", Objects.toString(defaultValue, null));
798

    
799
        state.set("index", index);
800
        state.set("maximumOccurrences", maximumOccurrences);
801
        state.set("minimumOccurrences", minimumOccurrences);
802
        state.set("size", size);
803
        state.set("name", name);
804
        state.set("objectClass", objectClass == null ? null : objectClass.getName());
805
        state.set("precision", precision);
806
        state.set("scale", scale);
807
        state.set("roundMode", roundMode);
808
        if (this.locale == null) {
809
            state.setNull("locale");
810
        } else {
811
            state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
812
        }
813
        state.set("evaluator", evaluator);
814

    
815
        state.set("primaryKey", primaryKey);
816
        state.set("readOnly", readOnly);
817
        state.set("SRS", SRS);
818
        GeometryType theGeomType = this.getGeomType();
819
        if (theGeomType == null) {
820
            state.set("geometryType", Geometry.TYPES.UNKNOWN);
821
            state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
822
        } else {
823
            state.set("geometryType", theGeomType.getType());
824
            state.set("geometrySubType", theGeomType.getSubType());
825
        }
826

    
827
//      FIXME: additionalInfo
828
        state.set("isAutomatic", isAutomatic);
829
        state.set("isTime", isTime);
830
        if (this.interval == null) {
831
            state.setNull("interval_start");
832
            state.setNull("interval_end");
833
        } else {
834
            state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
835
            state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
836
        }
837
        state.set("SRS", SRS);
838

    
839
//      FIXME: featureAttributeGetter
840
        if (featureAttributeEmulator instanceof Persistent) {
841
            state.set("featureAttributeEmulator", featureAttributeEmulator);
842
        } else {
843
            state.setNull("featureAttributeEmulator");
844
        }
845

    
846
        state.set("indexed", indexed);
847
        state.set("isIndexAscending", isIndexAscending);
848
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
849

    
850
        if (this.availableValues == null) {
851
            state.setNull("availableValues");
852
        } else {
853
            Map<String, Object> values = new LinkedHashMap<>();
854
            for (DynObjectValueItem value : availableValues) {
855
                values.put(value.getLabel(), value.getValue());
856
            }
857
            state.set("availableValues", values);
858
        }
859
        state.set("description", description);
860
        state.set("minValue", minValue);
861
        state.set("maxValue", maxValue);
862
        state.set("label", label);
863
        state.set("order", order);
864
        state.set("hidden", hidden);
865
        state.set("groupName", groupName);
866
        state.set("relationType", relationType);
867

    
868
        state.set("foreingKey", this.foreingKey);
869
        state.set("tags", this.tags);
870

    
871
        state.set("displaySize", displaySize);
872
        state.set("availableValuesExpression", availableValuesExpression);
873
        state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);
874
        state.set("defaultFormat", defaultFormat);
875
    }
876

    
877
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
878

    
879
    public static void registerPersistenceDefinition() {
880
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
881

    
882
        if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
883
                == null) {
884
            DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
885
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
886
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
887
                    + " persistent definition",
888
                    null,
889
                    null
890
            );
891
            definition.addDynFieldBoolean("allowNull");
892
            definition.addDynFieldInt("dataType");
893
            definition.addDynFieldString("dataProfile");
894
//            definition.addDynFieldString("dateFormat");
895
            definition.addDynFieldString("defaultValue");
896
            definition.addDynFieldInt("index");
897
            definition.addDynFieldInt("maximumOccurrences");
898
            definition.addDynFieldInt("minimumOccurrences");
899
            definition.addDynFieldInt("size");
900
            definition.addDynFieldString("name");
901
            definition.addDynFieldString("objectClass");
902
            definition.addDynFieldInt("precision");
903
            definition.addDynFieldInt("scale").setMandatory(false).setDefaultDynValue(DataType.SCALE_NONE);
904
            definition.addDynFieldInt("roundMode").setMandatory(false).setDefaultDynValue(BigDecimal.ROUND_HALF_UP);
905
            definition.addDynFieldString("locale").setMandatory(false).setDefaultDynValue("null");
906
            definition.addDynFieldObject("evaluator").setClassOfValue(Evaluator.class);
907
            definition.addDynFieldBoolean("primaryKey");
908
            definition.addDynFieldBoolean("readOnly");
909
            definition.addDynFieldObject("SRS")
910
                    .setClassOfValue(IProjection.class);
911
            definition.addDynFieldInt("geometryType");
912
            definition.addDynFieldInt("geometrySubType");
913
//            definition.addDynFieldMap("additionalInfo");
914
            definition.addDynFieldBoolean("isAutomatic");
915
            definition.addDynFieldBoolean("isTime");
916
            definition.addDynFieldLong("interval_start");
917
            definition.addDynFieldLong("interval_end");
918
            definition.addDynFieldObject("featureAttributeEmulator")
919
                    .setClassOfValue(FeatureAttributeEmulator.class);
920
            definition.addDynFieldBoolean("indexed");
921
            definition.addDynFieldBoolean("isIndexAscending");
922
            definition.addDynFieldBoolean("allowIndexDuplicateds");
923
            definition.addDynFieldMap("availableValues")
924
                    .setClassOfItems(Object.class);
925
            definition.addDynFieldString("description");
926
            definition.addDynFieldObject("minValue");
927
            definition.addDynFieldObject("maxValue");
928
            definition.addDynFieldString("label");
929
            definition.addDynFieldInt("order");
930
            definition.addDynFieldBoolean("hidden");
931
            definition.addDynFieldBoolean("avoidCachingAvailableValues");
932
            definition.addDynFieldString("groupName");
933
            definition.addDynFieldInt("relationType");
934

    
935
            definition.addDynFieldObject("foreingKey")
936
                    .setClassOfValue(DefaultForeingKey.class);
937

    
938
            definition.addDynFieldObject("tags")
939
                    .setClassOfValue(Tags.class);
940

    
941
            definition.addDynFieldInt("displaySize").setMandatory(false);
942
            definition.addDynFieldObject("availableValuesExpression")
943
                    .setClassOfValue(Expression.class)
944
                    .setMandatory(false);
945
            definition.addDynFieldString("defaultFormat").setMandatory(false);
946
        }
947
    }
948

    
949
    /*
950
     * Start of DynField interface Implementation
951
     *
952
     */
953
    @Override
954
    public Tags getTags() {
955
        return tags;
956
    }
957

    
958
    private Expression availableValuesFilter;
959

    
960
    @Override
961
    public Expression getAvailableValuesFilter() {
962
        return this.availableValuesFilter;
963
    }
964

    
965
    public FeatureAttributeDescriptor setAvailableValuesFilter(Expression filter) {
966
        this.availableValuesFilter = filter;
967
        return this;
968
    }
969

    
970
    public FeatureAttributeDescriptor setAvailableValuesFilter(String filter) {
971
        this.availableValuesFilter = ExpressionUtils.createExpression(filter);
972
        return this;
973
    }
974

    
975
    @Override
976
    public boolean hasConstantAvailableValues() {
977
        return this.availableValues != null;
978
    }
979

    
980
    @Override
981
    public boolean isAvoidCachingAvailableValues() {
982
        return this.avoidCachingAvailableValues;
983
    }
984

    
985
    public boolean hasAvailableValues() {
986
        return getAvailableValues() != null;
987
    }
988

    
989
    @Override
990
    public DynObjectValueItem[] getAvailableValues(DynObject context) {
991
        if (this.availableValuesMethod != null) {
992
            DynObjectValueItem[] values;
993
            try {
994
                values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(context, new Object[]{this});
995
            } catch (DynMethodException ex) {
996
                return this.getAvailableValues();
997
            }
998
            if (values != null) {
999
                return values;
1000
            }
1001
        }
1002
        Expression filter = this.availableValuesFilter;
1003
        if (!ExpressionUtils.isEmpty(filter)) {
1004
            if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1005
                ContextForeingKey foreingkeyContext = this.foreingKey.createContext();
1006
                foreingkeyContext.setContextValues(context);
1007
                DynObjectValueItem[] values = this.foreingKey.getAvailableValues(foreingkeyContext);
1008
                return values;
1009
            }
1010
            MutableSymbolTable contextSymbolTable = ExpressionUtils.createSymbolTable("feature", context);
1011
            MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
1012
            symbolTable.addSymbolTable(contextSymbolTable);
1013

    
1014
            DynObjectValueItem[] allValues = this.getAvailableValues();
1015
            List<DynObjectValueItem> filteredValues = new ArrayList<>();
1016
            for (DynObjectValueItem value : allValues) {
1017
                symbolTable.setVar("$value", value.getValue());
1018
                symbolTable.setVar("$label", value.getLabel());
1019
                Object include = filter.execute(symbolTable);
1020
                if (DataTypeUtils.isFalse(include, false)) {
1021
                    continue;
1022
                }
1023
                filteredValues.add(value);
1024
            }
1025
            DynObjectValueItem[] values = filteredValues.toArray(
1026
                    new DynObjectValueItem[filteredValues.size()]
1027
            );
1028
            return values;
1029
        }
1030
        return this.getAvailableValues();
1031
    }
1032

    
1033
    @Override
1034
    public boolean isAvailableValuesCalculated() {
1035
        if (this.availableValuesMethod != null) {
1036
            return true;
1037
        }
1038
        if (!ExpressionUtils.isEmpty(this.availableValuesFilter)) {
1039
            return true;
1040
        }
1041
        return false;
1042
    }
1043

    
1044
    @Override
1045
    public DynObjectValueItem[] getAvailableValues() {
1046
        DynObjectValueItem[] values = this.availableValues;
1047

    
1048
        if (values != null) {
1049
            return values;
1050
        }
1051
        values = this.availableValuesCache;
1052
        if (values != null) {
1053
            return values;
1054
        }
1055
        if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1056
            values = this.foreingKey.getAvailableValues(null);
1057

    
1058
        } else if (this.availableValuesExpression != null) {
1059
            values = this.getAvailableValuesFromExpression();
1060
        }
1061
        if (!this.avoidCachingAvailableValues) {
1062
            this.availableValuesCache = values;
1063
        }
1064
        return values;
1065
    }
1066

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

    
1201
    private DynObjectValueItem[] getAvailableValuesFromExpression() {
1202
        if (this.availableValuesExpression == null || this.availableValuesExpression.isEmpty()) {
1203
            return null;
1204
        }
1205
        try {
1206
            Object value = this.availableValuesExpression.execute(null);
1207
            if (value instanceof DynObjectValueItem[]) {
1208
                return (DynObjectValueItem[]) value;
1209
            }
1210
            if (value instanceof List) {
1211
                return this.getAvailableValuesFrom(new GetItemWithSize() {
1212
                    @Override
1213
                    public Object get(int i) {
1214
                        return ((List) value).get(i);
1215
                    }
1216

    
1217
                    @Override
1218
                    public int size() {
1219
                        return ((List) value).size();
1220
                    }
1221
                });
1222
            }
1223
        } catch (Throwable th) {
1224
            LOGGER.warn("Can't get available values from expression", th);
1225
        }
1226
        return null;
1227
    }
1228

    
1229
    @Override
1230
    public Expression getAvailableValuesExpression() {
1231
        return this.availableValuesExpression;
1232
    }
1233

    
1234
    @Override
1235
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1236
        if (StringUtils.isBlank(expression)) {
1237
            this.availableValuesExpression = null;
1238
            return this;
1239
        }
1240
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1241
        return this;
1242
    }
1243

    
1244
    @Override
1245
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1246
        this.availableValuesExpression = expression;
1247
        return this;
1248
    }
1249

    
1250
    @Override
1251
    public String getLabelOfValue(Object value) {
1252
        if (this.labelOfValueMap != null) {
1253
            String theLabel = this.labelOfValueMap.get(value);
1254
            if (theLabel == null) {
1255
                theLabel = Objects.toString(value, "");
1256
            }
1257
            return theLabel;
1258
        }
1259
        DynObjectValueItem[] values = this.getAvailableValues();
1260
        if (values == null) {
1261
            return Objects.toString(value, "");
1262
        }
1263
        Map<Object, String> map = new LinkedHashMap<>();
1264
        for (DynObjectValueItem theValue : values) {
1265
            map.put(theValue.getValue(), theValue.getLabel());
1266
        }
1267
        this.labelOfValueMap = map;
1268
        String theLabel = this.labelOfValueMap.get(value);
1269
        if (theLabel == null) {
1270
            theLabel = Objects.toString(value, "");
1271
        }
1272
        return theLabel;
1273
    }
1274

    
1275
    @Override
1276
    public String getDescription() {
1277
        if (this.description == null) {
1278
            return getName();
1279
        }
1280
        return this.description;
1281
    }
1282

    
1283
    @Override
1284
    public Object getMaxValue() {
1285
        return this.maxValue;
1286
    }
1287

    
1288
    @Override
1289
    public Object getMinValue() {
1290
        return this.minValue;
1291
    }
1292

    
1293
    @Override
1294
    public int getTheTypeOfAvailableValues() {
1295
        return 1;
1296
    }
1297

    
1298
    @Override
1299
    public int getType() {
1300
        if (featureAttributeGetter != null) {
1301
            return featureAttributeGetter.getDataType().getType();
1302
        }
1303
        return getDataType().getType();
1304
    }
1305

    
1306
    @Override
1307
    public boolean isMandatory() {
1308
        return !allowNull() || isPrimaryKey();
1309
    }
1310

    
1311
    @Override
1312
    public boolean isPersistent() {
1313
        return false;
1314
    }
1315

    
1316
    @Override
1317
    public DynField setAvailableValues(DynObjectValueItem[] values) {
1318
        if (ArrayUtils.isEmpty(values)) {
1319
            this.availableValues = null;
1320
        } else {
1321
            Coercion coercion = this.getCoercion();
1322
            this.availableValues = new DynObjectValueItem[values.length];
1323
            for (int i = 0; i < values.length; i++) {
1324
                DynObjectValueItem element = values[i];
1325
                Object value;
1326
                try {
1327
                    value = coercion.coerce(element.getValue());
1328
                } catch (CoercionException ex) {
1329
                    value = element.getValue();
1330
                }
1331
                this.availableValues[i] = new DynObjectValueItem(value, element.getLabel());
1332
            }
1333
        }
1334
        return this;
1335
    }
1336

    
1337
    @Override
1338
    public DynField setDescription(String description) {
1339
        this.description = description;
1340
        return this;
1341
    }
1342

    
1343
    @Override
1344
    public DynField setMandatory(boolean mandatory) {
1345
        throw new UnsupportedOperationException();
1346
    }
1347

    
1348
    @Override
1349
    public DynField setMaxValue(Object maxValue) {
1350
        try {
1351
            this.maxValue = this.coerce(maxValue);
1352
        } catch (CoercionException e) {
1353
            throw new IllegalArgumentException(e);
1354
        }
1355
        return this;
1356
    }
1357

    
1358
    @Override
1359
    public DynField setMinValue(Object minValue) {
1360
        try {
1361
            this.maxValue = this.coerce(minValue);
1362
        } catch (CoercionException e) {
1363
            throw new IllegalArgumentException(e);
1364
        }
1365
        return this;
1366
    }
1367

    
1368
    @Override
1369
    public DynField setPersistent(boolean persistent) {
1370
        throw new UnsupportedOperationException();
1371
    }
1372

    
1373
    @Override
1374
    public DynField setTheTypeOfAvailableValues(int type) {
1375
        throw new UnsupportedOperationException();
1376
    }
1377

    
1378
    @Override
1379
    public DynField setType(int type) {
1380
        throw new UnsupportedOperationException();
1381
    }
1382

    
1383
    @Override
1384
    @Deprecated
1385
    public DynField setDefaultDynValue(Object defaultValue) {
1386
        return this.setDefaultFieldValue(defaultValue);
1387
    }
1388

    
1389
    @Override
1390
    public DynField setDefaultFieldValue(Object defaultValue) {
1391
        this.defaultValue = defaultValue;
1392
        return this;
1393
    }
1394

    
1395
    @Override
1396
    public Class getClassOfValue() {
1397
        return null;
1398
    }
1399

    
1400
    @Override
1401
    public DynField getElementsType() {
1402
        return null;
1403
    }
1404

    
1405
    @Override
1406
    public DynField setClassOfValue(Class theClass)
1407
            throws DynFieldIsNotAContainerException {
1408
        throw new UnsupportedOperationException();
1409
    }
1410

    
1411
    @Override
1412
    public DynField setElementsType(DynStruct type)
1413
            throws DynFieldIsNotAContainerException {
1414
        throw new UnsupportedOperationException();
1415
    }
1416

    
1417
    @Override
1418
    public DynField setElementsType(int type)
1419
            throws DynFieldIsNotAContainerException {
1420
        throw new UnsupportedOperationException();
1421
    }
1422

    
1423
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1424
        this.dataProfile = dataProfile;
1425
        return this;
1426
    }
1427

    
1428
    @Override
1429
    public String getDataProfileName() {
1430
        return dataProfile;
1431
    }
1432

    
1433
    @Override
1434
    public DataProfile getDataProfile() {
1435
        if (StringUtils.isBlank(dataProfile)) {
1436
            return null;
1437
        }
1438
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1439
        return profile;
1440
    }
1441

    
1442
    @Override
1443
    public void validate(Object value) throws DynFieldValidateException {
1444

    
1445
        if (value == null && !this.allowNull()) {
1446
            throw new DynFieldValidateException(value, this, null);
1447
        }
1448

    
1449
        try {
1450
            this.dataType.coerce(value);
1451
        } catch (CoercionException e) {
1452
            throw new DynFieldValidateException(value, this, e);
1453
        }
1454

    
1455
        /*
1456
         * Other checks will be needed
1457
         */
1458
    }
1459

    
1460
    @Override
1461
    public String getSubtype() {
1462
        if (featureAttributeGetter != null) {
1463
            return featureAttributeGetter.getDataType().getSubtype();
1464
        }
1465
        return this.dataType.getSubtype();
1466
    }
1467

    
1468
    @Override
1469
    public Object coerce(Object value) throws CoercionException {
1470
        if (value == null) {
1471
            return value; // O debe devolver this.defaultValue
1472
        }
1473
        try {
1474
            return this.getDataType().coerce(value, this.getCoercionContext());
1475
        } catch (Exception ex) {
1476
            throw new RuntimeException(ex);
1477
        }
1478
    }
1479

    
1480
    @Override
1481
    public DynField setAvailableValues(List values) {
1482
        if (values == null || values.isEmpty()) {
1483
            this.availableValues = null;
1484
        } else {
1485
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1486
                    new DynObjectValueItem[values.size()]
1487
            );
1488
        }
1489
        return this;
1490
    }
1491

    
1492
    @Override
1493
    public String getGroup() {
1494
        return this.groupName;
1495
    }
1496

    
1497
    @Override
1498
    public int getOder() {
1499
        return this.order;
1500
    }
1501

    
1502
    @Override
1503
    public String getLabel() {
1504
        if (this.label == null) {
1505
            return this.getName();
1506
        }
1507
        return this.label;
1508
    }
1509

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

    
1519
    @Override
1520
    public DynField setLabel(String label) {
1521
        this.label = label;
1522
        return this;
1523
    }
1524

    
1525
    @Override
1526
    public DynField setShortLabel(String shortLabel) {
1527
        this.shortLabel = shortLabel;
1528
        return this;
1529
    }
1530

    
1531
    @Override
1532
    public String getShortLabel() {
1533
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1534
    }
1535

    
1536
    @Override
1537
    public String getLocalizedShortLabel() {
1538
        if (StringUtils.isBlank(shortLabel)) {
1539
            return this.getLocalizedLabel();
1540
        }
1541
        I18nManager i18n = ToolsLocator.getI18nManager();
1542
        return i18n.getTranslation(shortLabel);
1543
    }
1544

    
1545
    @Override
1546
    public DynField setGroup(String groupName) {
1547
        this.groupName = groupName;
1548
        return this;
1549
    }
1550

    
1551
    @Override
1552
    public DynField setOrder(int order) {
1553
        this.order = order;
1554
        return this;
1555
    }
1556

    
1557
    @Override
1558
    public DynField setHidden(boolean hidden) {
1559
        this.hidden = hidden;
1560
        return this;
1561
    }
1562

    
1563
    @Override
1564
    public boolean isHidden() {
1565
        return this.hidden;
1566
    }
1567

    
1568
    @Override
1569
    public DynField setReadOnly(boolean readOnly) {
1570
        this.readOnly = readOnly;
1571
        return this;
1572
    }
1573

    
1574
    @Override
1575
    public boolean isContainer() {
1576
        return false;
1577
    }
1578

    
1579
    @Override
1580
    public Class getClassOfItems() {
1581
        return null;
1582
    }
1583

    
1584
    @Override
1585
    public DynField setClassOfItems(Class theClass) {
1586
        throw new UnsupportedOperationException();
1587
    }
1588

    
1589
    @Override
1590
    public DynField setType(DataType type) {
1591
        throw new UnsupportedOperationException();
1592
    }
1593

    
1594
    @Override
1595
    public DynField setSubtype(String subtype) {
1596
        throw new UnsupportedOperationException();
1597
    }
1598

    
1599
    @Override
1600
    public boolean isTime() {
1601
        return isTime;
1602
    }
1603

    
1604
    @Override
1605
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1606
        return featureAttributeGetter;
1607
    }
1608

    
1609
    @Override
1610
    public void setFeatureAttributeGetter(
1611
            FeatureAttributeGetter featureAttributeTransform) {
1612
        this.featureAttributeGetter = featureAttributeTransform;
1613
    }
1614

    
1615
    @Override
1616
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1617
        return this.featureAttributeEmulator;
1618
    }
1619

    
1620
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1621
        this.featureAttributeEmulator = featureAttributeEmulator;
1622
        return this;
1623
    }
1624

    
1625
    @Override
1626
    public boolean isIndexed() {
1627
        return this.indexed;
1628
    }
1629

    
1630
    @Override
1631
    public boolean isForeingKey() {
1632
        return this.foreingKey != null && this.foreingKey.isForeingKey();
1633
    }
1634

    
1635
    @Override
1636
    public ForeingKey getForeingKey() {
1637
        return this.foreingKey;
1638
    }
1639

    
1640
    @Override
1641
    public boolean allowIndexDuplicateds() {
1642
        return this.allowIndexDuplicateds;
1643
    }
1644

    
1645
    @Override
1646
    public boolean isIndexAscending() {
1647
        return this.isIndexAscending;
1648
    }
1649

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

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

    
1660
    @Override
1661
    public String getClassNameOfValue() {
1662
        return null;
1663
    }
1664

    
1665
    @Override
1666
    public DynStruct getDynClassOfValue() {
1667
        return null;
1668
    }
1669

    
1670
    @Override
1671
    public DynField setTypeOfItems(int type) {
1672
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1673
    }
1674

    
1675
    @Override
1676
    public int getTypeOfItems() {
1677
        return DataTypes.INVALID;
1678
    }
1679

    
1680
    @Override
1681
    public DynField setClassOfItems(DynStruct dynStrct) {
1682
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1683
    }
1684

    
1685
    @Override
1686
    public DynField setClassOfItems(String theClassNameOfValue) {
1687
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1688
    }
1689

    
1690
    @Override
1691
    public String getClassNameOfItems() {
1692
        return null;
1693
    }
1694

    
1695
    @Override
1696
    public DynStruct getDynClassOfItems() {
1697
        return null;
1698
    }
1699

    
1700
    @Override
1701
    public DynField setRelationType(int relationType) {
1702
        this.relationType = relationType;
1703
        return this;
1704
    }
1705

    
1706
    @Override
1707
    public int getRelationType() {
1708
        return this.relationType;
1709
    }
1710

    
1711
    @Override
1712
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1713
        this.availableValuesMethod = availableValuesMethod;
1714
        return this;
1715
    }
1716

    
1717
    @Override
1718
    public DynMethod getAvailableValuesMethod() {
1719
        if (this.availableValuesMethod != null) {
1720
            return this.availableValuesMethod;
1721
        }
1722
        if (this.availableValuesFilter == null && !this.isForeingKey()) {
1723
            return null;
1724
        }
1725
        DynMethod method = new AbstractDynMethod("getAvailableValuesOf" + this.getName()) {
1726
            @Override
1727
            public Object invoke(DynObject context, Object[] args) throws DynMethodException {
1728
                return getAvailableValues(context);
1729
            }
1730
        };
1731
        return method;
1732
    }
1733

    
1734
    @Override
1735
    public DynMethod getCalculateMethod() {
1736
        return this.calculateMethod;
1737
    }
1738

    
1739
    @Override
1740
    public DynField setCalculateMethod(DynMethod method) {
1741
        this.calculateMethod = method;
1742
        return this;
1743
    }
1744

    
1745
    @Override
1746
    public boolean isCalculated() {
1747
        return this.calculateMethod != null;
1748
    }
1749

    
1750
    @Override
1751
    public Object getCalculatedValue(DynObject self) {
1752
        try {
1753
            return this.calculateMethod.invoke(self, new Object[]{this});
1754
        } catch (DynMethodException ex) {
1755
            throw new RuntimeException(ex);
1756
        }
1757
    }
1758

    
1759
    @Override
1760
    public DynField setValidateElements(boolean validate) {
1761
        return this;
1762
    }
1763

    
1764
    @Override
1765
    public boolean getValidateElements() {
1766
        return false;
1767
    }
1768

    
1769
    @Override
1770
    public boolean hasLabel() {
1771
        return StringUtils.isNotBlank(this.label);
1772
    }
1773

    
1774
    @Override
1775
    public boolean hasShortLabel() {
1776
        return StringUtils.isNotBlank(this.shortLabel);
1777
    }
1778

    
1779
    @Override
1780
    public boolean hasDescription() {
1781
        return StringUtils.isNotBlank(this.description);
1782
    }
1783

    
1784
    @Override
1785
    public FeatureAttributeDescriptor getValue() {
1786
        return this;
1787
    }
1788

    
1789
    @Override
1790
    public int getDisplaySize() {
1791
        return this.displaySize;
1792
    }
1793

    
1794
    @Override
1795
    public boolean isInAvailableValues(Object valueToCheck) {
1796
        if (this.getAvailableValues() != null) {
1797
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1798
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1799
                    return true;
1800
                }
1801
            }
1802
        }
1803
        return false;
1804
    }
1805

    
1806
    private class ConstantValueEvaluator extends AbstractEvaluator {
1807

    
1808
        @Override
1809
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1810
            return defaultValue;
1811
        }
1812

    
1813
        @Override
1814
        public String getName() {
1815
            return "Constant attribute " + name;
1816
        }
1817
    }
1818

    
1819
    public void setConstantValue(boolean isConstantValue) {
1820
        if (isConstantValue) {
1821
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1822
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1823
             * el evaluador el que se encarga de proporcionar su valor.
1824
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1825
             * por defecto para ese attributo.
1826
             */
1827
            this.evaluator = new ConstantValueEvaluator();
1828
        } else {
1829
            this.evaluator = null;
1830
        }
1831
    }
1832

    
1833
    @Override
1834
    public boolean isComputed() {
1835
        return featureAttributeEmulator != null || evaluator != null || isCalculated();
1836
    }
1837

    
1838
    @Override
1839
    public FeatureStore getStore() {
1840
        FeatureType ftype = this.getFeatureType();
1841
        if (ftype == null) {
1842
            return null;
1843
        }
1844
        return ftype.getStore();
1845
    }
1846

    
1847
    @Override
1848
    public FeatureType getFeatureType() {
1849
        if (this.typeRef == null) {
1850
            return null;
1851
        }
1852
        FeatureType ftype = (FeatureType) this.typeRef.get();
1853
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1854
        return ftype;
1855
    }
1856

    
1857
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1858
        this.interval = interval;
1859
        return this;
1860
    }
1861

    
1862
    public void fixAll() {
1863
        if (!this.getDataType().supportSize()) {
1864
            this.size = 0;
1865
        }
1866
        NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1867
        this.precision = ps.getPrecision();
1868
        this.scale = ps.getScale();
1869

    
1870
        switch (this.getType()) {
1871
            case DataTypes.INSTANT:
1872
            case DataTypes.INTERVAL:
1873
            case DataTypes.DATE:
1874
            case DataTypes.TIME:
1875
            case DataTypes.TIMESTAMP:
1876
                if (this.getInterval() != null) {
1877
                    this.isTime = true;
1878
                }
1879
                break;
1880
        }
1881
    }
1882

    
1883
    @Override
1884
    public String[] getRequiredFieldNames() {
1885
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1886
        if (emulator == null) {
1887
            return null;
1888
        }
1889
        return emulator.getRequiredFieldNames();
1890
    }
1891

    
1892
    @Override
1893
    public void recentUsed() {
1894
        DefaultFeatureType.RECENTS_USEDS.add(this);
1895
    }
1896

    
1897
    @Override
1898
    public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1899
        if (other == null) {
1900
            throw new NullPointerException();
1901
        }
1902
        DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1903
        if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1904
            return false;
1905
        }
1906
        if (old.isComputed() && old.isComputed() == this.isComputed()) {
1907
            return true;
1908
        }
1909
        if (this.dataType != old.dataType) {
1910
            return false;
1911
        }
1912
        if (this.size != old.size) {
1913
            return false;
1914
        }
1915
        if (this.precision != old.precision) {
1916
            return false;
1917
        }
1918
//        if( this.primaryKey != old.primaryKey ) {
1919
//            return false;
1920
//        }
1921
        if (this.geomType != old.geomType) {
1922
            return false;
1923
        }
1924
        if (this.SRS != old.SRS) {
1925
            return false;
1926
        }
1927
        if (this.isAutomatic != old.isAutomatic) {
1928
            return false;
1929
        }
1930
        return true;
1931
    }
1932

    
1933
    private class PropertiesBuilder {
1934

    
1935
        private String name;
1936
        private DataType type;
1937
        private Map<String, String> sets;
1938
        private String sep;
1939

    
1940
        public PropertiesBuilder() {
1941
            this.sets = new LinkedHashMap<>();
1942
        }
1943

    
1944
        public void separator(String sep) {
1945
            this.sep = sep;
1946
        }
1947

    
1948
        public void name(String name) {
1949
            this.name = name;
1950
        }
1951

    
1952
        public void type(DataType type) {
1953
            this.type = type;
1954
        }
1955

    
1956
        public void set(String name, ForeingKey fk) {
1957
            if (fk == null) {
1958
                return;
1959
            }
1960
            if (!fk.isForeingKey()) {
1961
                return;
1962
            }
1963
            this.set(name, fk.isForeingKey());
1964
            this.set(name + "_code", fk.getCodeName());
1965
            this.set(name + "_label", fk.getLabelFormula());
1966
            this.set(name + "_closedlist", fk.isClosedList());
1967
            this.set(name + "_table", fk.getTableName());
1968
        }
1969

    
1970
        public void set(String name, FeatureAttributeEmulator value) {
1971
            if (value == null) {
1972
                return;
1973
            }
1974
            if (value instanceof FeatureAttributeEmulatorExpression) {
1975
                this.set(name, ((FeatureAttributeEmulatorExpression) value).getExpression().getPhrase());
1976
            }
1977
        }
1978

    
1979
        public void set(String name, IProjection value) {
1980
            if (value == null) {
1981
                return;
1982
            }
1983
            this.set(name, value.getAbrev());
1984
        }
1985

    
1986
        public void set(String name, GeometryType value) {
1987
            if (value == null) {
1988
                return;
1989
            }
1990
            this.set(name, value.getFullName().replace(":", "@"));
1991
        }
1992

    
1993
        public void set(String name, Object value) {
1994
            if (value == null) {
1995
                return;
1996
            }
1997
            String s = Objects.toString(value, "");
1998
            if (StringUtils.isBlank(s)) {
1999
                return;
2000
            }
2001
            this.sets.put(name, s);
2002
        }
2003

    
2004
        public void set(String name, Object value, Object skipValue) {
2005
            if (value == null || value == skipValue) {
2006
                return;
2007
            }
2008
            String s = Objects.toString(value, "");
2009
            if (StringUtils.isBlank(s)) {
2010
                return;
2011
            }
2012
            this.sets.put(name, s);
2013
        }
2014

    
2015
        @Override
2016
        public String toString() {
2017
            StringBuilder builder = new StringBuilder();
2018
            builder.append(this.name);
2019
            builder.append(sep);
2020
            builder.append(this.type.getName());
2021
            for (String key : this.sets.keySet()) {
2022
                builder.append(sep);
2023
                builder.append("set");
2024
                builder.append(sep);
2025
                builder.append(key);
2026
                builder.append("=");
2027
                builder.append(this.sets.get(key));
2028
            }
2029
            return builder.toString();
2030
        }
2031
    }
2032

    
2033
    private String getAll() {
2034
        PropertiesBuilder builder = new PropertiesBuilder();
2035
        builder.separator("/");
2036
        builder.name(this.name);
2037
        builder.type(this.dataType);
2038
        builder.set("size", this.size, 0);
2039
        switch (this.getType()) {
2040
            case DataTypes.BYTE:
2041
            case DataTypes.INTEGER:
2042
            case DataTypes.LONG:
2043
                break;
2044
            case DataTypes.FLOAT:
2045
            case DataTypes.DOUBLE:
2046
                builder.set("locale", this.getLocale());
2047
                break;
2048
            case DataTypes.DECIMAL:
2049
                builder.set("precision", this.precision);
2050
                builder.set("scale", this.scale);
2051
                builder.set("roundMode", this.getRoundMode());
2052
                builder.set("locale", this.getLocale());
2053
                break;
2054
            case DataTypes.DATE:
2055
            case DataTypes.TIME:
2056
            case DataTypes.TIMESTAMP:
2057
                builder.set("locale", this.getLocale());
2058
                break;
2059
            case DataTypes.GEOMETRY:
2060
                IProjection proj = this.getSRS();
2061
                if (proj != null) {
2062
                    builder.set("srs", proj.getAbrev().replace(":", "@"));
2063
                }
2064
                GeometryType theGeomType = this.getGeomType();
2065
                if (theGeomType != null) {
2066
                    String geomTypeName = GeometryUtils.getGeometryTypeName(this.getGeomType().getType());
2067
                    String geomSubtypeName = GeometryUtils.getGeometrySubtypeName(this.getGeomType().getSubType());
2068
                    builder.set("geomtype", geomTypeName + "@" + geomSubtypeName);
2069
                }
2070
                break;
2071
        }
2072
        builder.set("hidden", this.isHidden(), false);
2073
        builder.set("readOnly", this.isReadOnly(), false);
2074
        builder.set("allowNull", this.allowNull(), true);
2075
        builder.set("pk", this.isPrimaryKey(), false);
2076
        builder.set("automatic", this.isAutomatic(), false);
2077
        builder.set("isTime", this.isTime(), false);
2078
        builder.set("profile", this.getDataProfileName());
2079
        builder.set("group", this.getGroup());
2080
        builder.set("description", this.description);
2081
        builder.set("label", this.label);
2082
        builder.set("shortLabel", this.shortLabel);
2083
        builder.set("order", this.getOder());
2084
        if (this.getFeatureAttributeEmulator() instanceof FeatureAttributeEmulatorExpression) {
2085
            Expression exp = ((FeatureAttributeEmulatorExpression) this.getFeatureAttributeEmulator()).getExpression();
2086
            if (exp != null) {
2087
                builder.set("expression", exp.getPhrase());
2088
            }
2089
        }
2090
        builder.set("isAvoidCachingAvailableValues", this.isAvoidCachingAvailableValues(), false);
2091
        if (this.isForeingKey()) {
2092
            builder.set("fk", this.isForeingKey());
2093
            builder.set("fk_table", this.getForeingKey().getTableName());
2094
            builder.set("fk_code", this.getForeingKey().getCodeName());
2095
            builder.set("fk_label", this.getForeingKey().getLabelFormula());
2096
            builder.set("fk.closedlist", this.getForeingKey().isClosedList());
2097
        }
2098
        return builder.toString();
2099
    }
2100

    
2101
    @Override
2102
    public Object get(String name) {
2103
        if (StringUtils.isBlank(name)) {
2104
            throw new IllegalArgumentException("Name can't be empty");
2105
        }
2106
        switch (name.trim().toLowerCase()) {
2107
            case "all":
2108
                return this.getAll();
2109
            case "isreadonly":
2110
            case "readonly":
2111
                return this.isReadOnly();
2112
            case "hidden":
2113
                return this.isHidden();
2114
            case "allownull":
2115
                return this.allowNull();
2116
            case "pk":
2117
            case "ispk":
2118
            case "primarykey":
2119
            case "isprimarykey":
2120
                return this.isPrimaryKey();
2121
            case "isautomatic":
2122
            case "automatic":
2123
                return this.isAutomatic();
2124
            case "time":
2125
            case "istime":
2126
                return this.isTime();
2127
            case "profile":
2128
                return this.getDataProfile();
2129
            case "group":
2130
                return this.getGroup();
2131
            case "description":
2132
                return this.getDescription();
2133
            case "label":
2134
                return this.getLabel();
2135
            case "shortlabel":
2136
                return this.getShortLabel();
2137
            case "isavoidcachingavailablevalues":
2138
            case "avoidcachingavailablevalues":
2139
            case "nocachingavailablevalues":
2140
                return this.isAvoidCachingAvailableValues();
2141
            case "expression":
2142
                return this.getFeatureAttributeEmulator();
2143
            case "size":
2144
                return this.getSize();
2145
            case "precision":
2146
                return this.getPrecision();
2147
            case "scale":
2148
                return this.getScale();
2149
            case "roundmode":
2150
                return this.getRoundMode();
2151
            case "locale":
2152
                return this.getLocale();
2153
            case "order":
2154
                return this.getOder();
2155
            case "isfk":
2156
            case "isforeingkey":
2157
                return this.isForeingKey();
2158
            case "fk":
2159
            case "foreingkey":
2160
                return this.getForeingKey();
2161
            case "fk_code":
2162
            case "foreingkey_code":
2163
            case "foreingkey.code":
2164
                return this.getForeingKey().getCodeName();
2165
            case "fk_label":
2166
            case "foreingkey_label":
2167
            case "foreingkey.label":
2168
                return this.getForeingKey().getLabelFormula();
2169
            case "fk.closedlist":
2170
            case "foreingkey_closedlist":
2171
            case "foreingkey.closedlist":
2172
                return this.getForeingKey().isClosedList();
2173
            case "fk_table":
2174
            case "foreingkey_table":
2175
            case "foreingkey.table":
2176
                return this.getForeingKey().getTableName();
2177
            case "interval":
2178
                return this.getInterval();
2179
            case "geomtype":
2180
            case "geometrytype":
2181
                return this.getGeomType();
2182
            case "srs":
2183
                return this.getSRS();
2184
            default:
2185
                throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
2186
        }
2187
    }
2188

    
2189
    public void setSRSForced(IProjection SRS) {
2190
        this.SRS = SRS;
2191
    }
2192

    
2193
    @Override
2194
    public JsonObject toJson() {
2195
        return this.toJsonBuilder().build();
2196
    }
2197

    
2198
    @Override
2199
    public JsonObjectBuilder toJsonBuilder() {
2200
        JsonObjectBuilder builder = Json.createObjectBuilder();
2201
        builder.add_class(this);
2202
        builder.add("name", this.name);
2203
        builder.add("description", this.description);
2204
        builder.add("label", this.label);
2205
        builder.add("shortLabel", this.shortLabel);
2206
        builder.add("order", this.order);
2207
        builder.add("groupName", this.groupName);
2208
        builder.add("dataType", this.dataType);
2209
        builder.add("size", this.size);
2210
        builder.add("precision", this.precision);
2211
        builder.add("scale", this.scale);
2212
        builder.add("roundMode", this.roundMode);
2213

    
2214
        builder.add("allowNull", this.allowNull);
2215
        builder.add("primaryKey", this.primaryKey);
2216
        builder.add("readOnly", this.readOnly);
2217
        builder.add("isAutomatic", this.isAutomatic);
2218
        builder.add("isTime", this.isTime);
2219
        builder.add("indexed", this.indexed);
2220
        builder.add("isIndexAscending", this.isIndexAscending);
2221
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2222
        builder.add("hidden", this.hidden);
2223
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2224

    
2225
        builder.add("geometryType", this.getGeomType());
2226
        builder.add("srs", this.getSRS());
2227

    
2228
        builder.add("relationType", this.relationType);
2229
        builder.add("displaySize", this.displaySize);
2230
        builder.add("locale", this.getLocale());
2231
        builder.add("expression", this.getFeatureAttributeEmulator());
2232
        if (this.isForeingKey()) {
2233
            builder.add("fk", this.isForeingKey());
2234
            builder.add("fk_table", this.getForeingKey().getTableName());
2235
            builder.add("fk_code", this.getForeingKey().getCodeName());
2236
            builder.add("fk_label", this.getForeingKey().getLabelFormula());
2237
            builder.add("fk_closedlist", this.getForeingKey().isClosedList());
2238
        }
2239
        builder.add("availableValuesExpression", this.availableValuesExpression);
2240
        builder.add("defaultValue", Objects.toString(this.defaultValue, null));
2241
        builder.add("dataProfile", this.getDataProfileName());
2242
        builder.add("tags", tags);
2243
        builder.add("availableValues", availableValues);
2244
        builder.add("additionalInfo", this.additionalInfo);
2245
        builder.add("defaultFormat", this.defaultFormat);
2246
        return builder;
2247
    }
2248

    
2249
    public void fromJson(JsonObject json) {
2250
        this.name = json.getString("name");
2251
        this.description = json.getString("description");
2252
        this.label = json.getString("label");
2253
        this.shortLabel = json.getString("shortLabel");
2254
        this.order = json.getInt("order");
2255
        this.groupName = json.getString("groupName");
2256
        this.precision = json.getInt("precision");
2257
        this.size = json.getInt("size");
2258
        this.scale = json.getInt("scale");
2259
        this.roundMode = json.getInt("roundMode");
2260

    
2261
        this.allowNull = json.getBoolean("allowNull");
2262
        this.primaryKey = json.getBoolean("primaryKey");
2263
        this.readOnly = json.getBoolean("readOnly");
2264
        this.isAutomatic = json.getBoolean("isAutomatic");
2265
        this.isTime = json.getBoolean("isTime");
2266
        this.indexed = json.getBoolean("indexed");
2267
        this.isIndexAscending = json.getBoolean("isIndexAscending");
2268
        this.allowIndexDuplicateds = json.getBoolean("allowIndexDuplicateds");
2269
        this.hidden = json.getBoolean("hidden");
2270
        this.avoidCachingAvailableValues = json.getBoolean("avoidCachingAvailableValues");
2271

    
2272
        this.relationType = json.getInt("relationType");
2273
        this.displaySize = json.getInt("displaySize");
2274

    
2275
        this.dataType = (DataType) Json.toObject(json, "dataType");
2276
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2277
        this.SRS = (IProjection) Json.toObject(json, "srs");
2278
        this.locale = (Locale) Json.toObject(json, "locale");
2279
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json, "expression");
2280

    
2281
        this.tags = (Tags) Json.toObject(json, "tags");
2282
        this.additionalInfo = Json.toMap(json, "additionalInfo");
2283
        this.availableValues = (DynObjectValueItem[]) Json.toArray(json, "availableValues", new DynObjectValueItem[0]);
2284
        this.dataProfile = json.getString("dataProfile", null);
2285
        try {
2286
            this.defaultValue = json.getString("defaultValue", null);
2287
            if(!(this.defaultValue instanceof String && ExpressionUtils.isDynamicText((String) this.defaultValue))){
2288
                this.defaultValue = this.coerce(this.defaultValue);
2289
            }
2290
        } catch (Exception ex) {
2291
            LOGGER.warn("Can't retrive default value for attribute '" + this.name + "'.", ex);
2292
        }
2293
        this.availableValuesExpression = (Expression) Json.toObject(json, "availableValuesExpression");
2294
        if (json.getBoolean("fk", false)) {
2295
            this.foreingKey = new DefaultForeingKey();
2296
            this.foreingKey.setForeingKey(true);
2297
            this.foreingKey.setTableName(json.getString("fk_table", null));
2298
            this.foreingKey.setCodeName(json.getString("fk_code", null));
2299
            this.foreingKey.setLabelFormula(json.getString("fk_label", null));
2300
            this.foreingKey.setClosedList(json.getBoolean("fk_closedlist", false));
2301
        } else {
2302
            this.foreingKey = null;
2303
        }
2304
        this.description = json.getString("defaultFormat",null);
2305
    }
2306

    
2307
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2308

    
2309
        public TheJsonSerializer() {
2310
        }
2311

    
2312
        @Override
2313
        public Class getObjectClass() {
2314
            return DefaultFeatureAttributeDescriptor.class;
2315
        }
2316

    
2317
        @Override
2318
        public Object toObject(JsonObject json) {
2319
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2320
            o.fromJson(json);
2321
            return o;
2322
        }
2323

    
2324
        @Override
2325
        public JsonObjectBuilder toJsonBuilder(Object value) {
2326
            return ((SupportToJson) value).toJsonBuilder();
2327
        }
2328

    
2329
    }
2330

    
2331
    public static void selfRegister() {
2332
        Json.registerSerializer(new TheJsonSerializer());
2333
    }
2334

    
2335
    @Override
2336
    public String getDefaultFormat() {
2337
        return this.defaultFormat;
2338
    }
2339

    
2340
    @Override
2341
    public String format(Object value) {
2342
        try {
2343
            if( StringUtils.isBlank(this.defaultFormat)) {
2344
                if( this.locale==null ) { // !this.hasLocale()
2345
                    return DataTypeUtils.toString(Locale.getDefault(), value, Objects.toString(value, ""));
2346
                } else {
2347
                    return DataTypeUtils.toString(this.locale, value, Objects.toString(value, ""));
2348
                }
2349
            }
2350
            return String.format(this.defaultFormat, value);
2351
        } catch(Exception ex) {
2352
            return Objects.toString(value, "");
2353
        }
2354
    }
2355

    
2356
    
2357
}