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

History | View | Annotate | Download (81.4 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
//        TODO: Habria que meter este cambio en proximos builds 2022/11/16.
332
//        if( this.isPrimaryKey() ) {
333
//            return false;
334
//        }
335
        return allowNull;
336
    }
337

    
338
    @Override
339
    public Locale getLocale() {
340
        // FIXME: Debe devolver el locale que toca ENGLISH o default, 
341
        // pero no asignarlo a "locale", manteniendo el null en la variable.
342
        // Ojo que tambien habria que tocar el setLocale.
343
        if (this.locale == null) {
344
            if (this.dataType.isNumeric()) {
345
                this.locale = Locale.ENGLISH; //return
346
            } else {
347
                this.locale = Locale.getDefault();
348
            }
349
        }
350
        return this.locale;
351
    }
352

    
353
    @Override
354
    public DataType getDataType() {
355
        if (featureAttributeGetter != null) {
356
            return featureAttributeGetter.getDataType();
357
        }
358
        return this.dataType;
359
    }
360

    
361
    public FeatureAttributeDescriptor setDataType(int type) {
362
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
363
        return this;
364
    }
365

    
366
    @Override
367
    public DateFormat getDateFormat() {
368
        return this.dateFormat;
369
    }
370

    
371
    @Override
372
    public Object getDefaultValue() {
373
        return this.defaultValue;
374
    }
375

    
376
    @Override
377
    @Deprecated
378
    public Object getDefaultValueCoerced() {
379
        return getCoercedDefaultValue();
380
    }
381

    
382
    @Override
383
    public Object getCoercedDefaultValue() {
384
        try {
385
            Object value = this.defaultValue;
386
            if (value == null) {
387
                return null;
388
            }
389
            if (ExpressionUtils.isDynamicText(value.toString())) {
390
                value = ExpressionUtils.evaluateDynamicText(value.toString());
391
            }
392
            return this.getDataType().coerce(value);
393
        } catch (CoercionException ex) {
394
            return null;
395
        }
396
    }
397

    
398
    @Override
399
    public Supplier getDefaultValueSupplier() {
400
        return (Supplier) this::getDefaultValueCoerced;
401
    }
402

    
403
    @Override
404
    public DynField setDefaultValueSupplier(Supplier supplier) {
405
        //Do nothing
406
        return this;
407
    }
408

    
409
    @Override
410
    public Evaluator getEvaluator() {
411
        return this.evaluator;
412
    }
413

    
414
    @Override
415
    public int getGeometryType() {
416
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
417
            return Geometry.TYPES.UNKNOWN;
418
        }
419
        return this.geometryType;
420
    }
421

    
422
    @Override
423
    public int getGeometrySubType() {
424
        if (this.dataType.getType() != DataTypes.GEOMETRY) {
425
            return Geometry.SUBTYPES.UNKNOWN;
426
        }
427
        return this.geometrySubType;
428
    }
429

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

    
450
    @Override
451
    public int getIndex() {
452
        return this.index;
453
    }
454

    
455
    protected FeatureAttributeDescriptor setIndex(int index) {
456
        this.index = index;
457
        return this;
458
    }
459

    
460
    @Override
461
    public int getMaximumOccurrences() {
462
        return this.maximumOccurrences;
463
    }
464

    
465
    @Override
466
    public int getMinimumOccurrences() {
467
        return this.minimumOccurrences;
468
    }
469

    
470
    @Override
471
    public String getName() {
472
        return this.name;
473
    }
474

    
475
    public FeatureAttributeDescriptor setName(String name) {
476
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
477
        this.name = name;
478
        return this;
479
    }
480

    
481
    @Override
482
    public Class getObjectClass() {
483
        if (getDataType().getType() == DataTypes.OBJECT) {
484
            return objectClass;
485
        }
486
        return getDataType().getDefaultClass();
487
    }
488

    
489
    @Override
490
    public int getPrecision() {
491
        return this.precision;
492
    }
493

    
494
    @Override
495
    public int getScale() {
496
        return this.scale;
497
    }
498

    
499
    @Override
500
    public Coercion getCoercion() {
501
        return this.getDataType().getCoercion();
502
    }
503

    
504
    @Override
505
    public MathContext getMathContext() {
506
        if (this.mathContext == null) {
507
            if (this.getDataType().isNumeric()) {
508
                this.mathContext = new MathContext(
509
                        this.getPrecision(),
510
                        RoundingMode.valueOf(this.getRoundMode())
511
                );
512
            } else {
513
                this.mathContext = MathContext.UNLIMITED;
514
            }
515
        }
516
        return this.mathContext;
517
    }
518

    
519
    @Override
520
    public CoercionContext getCoercionContext() {
521
        if (this.coerceContext == null) {
522
            if (this.getDataType().isNumeric()) {
523
                this.coerceContext = DataTypeUtils.coerceContextDecimal(
524
                        this.getLocale(),
525
                        this.getPrecision(),
526
                        this.getScale(),
527
                        this.getRoundMode()
528
                );
529
            } else if (this.getType() == DataTypes.GEOMETRY) {
530
                GeometryCoercionContext context = GeometryLocator.getGeometryManager().createGeometryCoercionContext();
531
                context.setGeometryType(this.getGeomType());
532
                context.setMode(GeometryCoercionContext.MODE_ONERROR_DONTCONVERT);
533
                this.coerceContext = context;
534
            } else if (this.getType() == DataTypes.TIMESTAMP) {
535
//                if(this.locale != null){
536
                    this.coerceContext = DataTypeUtils.coerceContextLocale(
537
                            this.locale
538
                    );
539
//                }
540
            } else {
541
                this.coerceContext = DataTypeUtils.coerceContextLocale(
542
                        this.getLocale()
543
                );
544
            }
545
        }
546
        return this.coerceContext;
547
    }
548

    
549
    @Override
550
    public int getRoundMode() {
551
        return this.roundMode;
552
    }
553

    
554
    @Override
555
    public IProjection getSRS() {
556
        return this.SRS;
557
    }
558

    
559
    @Override
560
    public Interval getInterval() {
561
        return this.interval;
562
    }
563

    
564
    public IProjection getSRS(WeakReference storeRef) {
565
        if (this.SRS == null) {
566
            FeatureStore store = (FeatureStore) storeRef.get();
567
            this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
568
        }
569
        return this.SRS;
570
    }
571

    
572
    @Override
573
    public int getSize() {
574
        return this.size;
575
    }
576

    
577
    @Override
578
    public boolean isPrimaryKey() {
579
        return this.primaryKey;
580
    }
581

    
582
    @Override
583
    public boolean isReadOnly() {
584
        if (this.readOnly) {
585
            return true;
586
        }
587
        return this.isComputed();
588
    }
589

    
590
    @Override
591
    public String getAdditionalInfo(String infoName) {
592
        if (this.additionalInfo == null) {
593
            return null;
594
        }
595
        return this.additionalInfo.get(infoName);
596
    }
597

    
598
    @Override
599
    public boolean isAutomatic() {
600
        return this.isAutomatic;
601
    }
602

    
603
    @Override
604
    public boolean equals(Object obj) {
605
        if (this == obj) {
606
            return true;
607
        }
608
        if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
609
            return false;
610
        }
611
        DefaultFeatureAttributeDescriptor other
612
                = (DefaultFeatureAttributeDescriptor) obj;
613

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

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

    
622
        if (!Objects.equals(this.name, other.name)) {
623
            return false;
624
        }
625

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

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

    
634
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
635
            return false;
636
        }
637
        if (!Objects.equals(this.defaultFormat, other.defaultFormat)) {
638
            return false;
639
        }
640

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

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

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

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

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

    
661
        if (this.minimumOccurrences != other.minimumOccurrences) {
662
            return false;
663
        }
664

    
665
        if (this.geometryType != other.geometryType) {
666
            return false;
667
        }
668

    
669
        if (this.geometrySubType != other.geometrySubType) {
670
            return false;
671
        }
672

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

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

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

    
685
        if (!Objects.equals(this.dateFormat, other.dateFormat)) {
686
            return false;
687
        }
688

    
689
        if (!Objects.equals(this.objectClass, other.objectClass)) {
690
            return false;
691
        }
692

    
693
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
694
            return false;
695
        }
696

    
697
        return true;
698
    }
699

    
700
    @Override
701
    public void loadFromState(PersistentState state)
702
            throws PersistenceException {
703
        allowNull = state.getBoolean("allowNull");
704
        dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
705
        dataProfile = state.getString("dataProfile");
706

    
707
//        FIXME: dateFormat;
708
        try {
709
            defaultValue = dataType.coerce(state.get("defaultValue"));
710
        } catch (CoercionException ex) {
711
        }
712

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

    
759
        Map<String, Object> values = state.getMap("availableValues");
760
        if (values == null || values.isEmpty()) {
761
            this.availableValues = null;
762
        } else {
763
            this.availableValues = new DynObjectValueItem[values.size()];
764
            int n = 0;
765
            Coercion coercion = this.getCoercion();
766
            for (Entry<String, Object> entry : values.entrySet()) {
767
                Object value;
768
                try {
769
                    value = coercion.coerce(entry.getValue());
770
                } catch (CoercionException ex) {
771
                    value = entry.getValue();
772
                }
773
                this.availableValues[n++] = new DynObjectValueItem(value, entry.getKey());
774
            }
775
        }
776

    
777
        description = state.getString("description");
778
        minValue = state.get("minValue");
779
        maxValue = state.get("maxValue");
780
        label = state.getString("label");
781
        order = state.getInt("order");
782
        hidden = state.getBoolean("hidden");
783
        groupName = state.getString("groupName");
784
        relationType = state.getInt("relationType", RELATION_TYPE_NONE);
785

    
786
        foreingKey = (DefaultForeingKey) state.get("foreingKey");
787
        if (foreingKey != null) {
788
            this.foreingKey.setDescriptor(this);
789
        }
790
        tags = (Tags) state.get("tags");
791
        if (tags == null) {
792
            this.tags = new DefaultTags();
793
        }
794
        displaySize = state.getInt("displaySize", 0);
795
        availableValuesExpression = (Expression) state.get("availableValuesExpression");
796
        avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues", false);
797
        availableValuesCache = null;
798
        defaultFormat = state.getString("defaultFormat");
799
    }
800

    
801
    @Override
802
    public void saveToState(PersistentState state) throws PersistenceException {
803
        Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
804

    
805
        state.set("allowNull", allowNull);
806
        state.set("dataType", dataType.getType());
807
        state.set("dataProfile", dataProfile);
808

    
809
//        FIXME: dateFormat;
810
        state.set("defaultValue", Objects.toString(defaultValue, null));
811

    
812
        state.set("index", index);
813
        state.set("maximumOccurrences", maximumOccurrences);
814
        state.set("minimumOccurrences", minimumOccurrences);
815
        state.set("size", size);
816
        state.set("name", name);
817
        state.set("objectClass", objectClass == null ? null : objectClass.getName());
818
        state.set("precision", precision);
819
        state.set("scale", scale);
820
        state.set("roundMode", roundMode);
821
        if (this.locale == null) {
822
            state.setNull("locale");
823
        } else {
824
            state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
825
        }
826
        state.set("evaluator", evaluator);
827

    
828
        state.set("primaryKey", primaryKey);
829
        state.set("readOnly", readOnly);
830
        state.set("SRS", SRS);
831
        GeometryType theGeomType = this.getGeomType();
832
        if (theGeomType == null) {
833
            state.set("geometryType", Geometry.TYPES.UNKNOWN);
834
            state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
835
        } else {
836
            state.set("geometryType", theGeomType.getType());
837
            state.set("geometrySubType", theGeomType.getSubType());
838
        }
839

    
840
//      FIXME: additionalInfo
841
        state.set("isAutomatic", isAutomatic);
842
        state.set("isTime", isTime);
843
        if (this.interval == null) {
844
            state.setNull("interval_start");
845
            state.setNull("interval_end");
846
        } else {
847
            state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
848
            state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
849
        }
850
        state.set("SRS", SRS);
851

    
852
//      FIXME: featureAttributeGetter
853
        if (featureAttributeEmulator instanceof Persistent) {
854
            state.set("featureAttributeEmulator", featureAttributeEmulator);
855
        } else {
856
            state.setNull("featureAttributeEmulator");
857
        }
858

    
859
        state.set("indexed", indexed);
860
        state.set("isIndexAscending", isIndexAscending);
861
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
862

    
863
        if (this.availableValues == null) {
864
            state.setNull("availableValues");
865
        } else {
866
            Map<String, Object> values = new LinkedHashMap<>();
867
            for (DynObjectValueItem value : availableValues) {
868
                if( value!=null ) {
869
                    values.put(value.getLabel(), value.getValue());
870
                }
871
            }
872
            state.set("availableValues", values);
873
        }
874
        state.set("description", description);
875
        state.set("minValue", minValue);
876
        state.set("maxValue", maxValue);
877
        state.set("label", label);
878
        state.set("order", order);
879
        state.set("hidden", hidden);
880
        state.set("groupName", groupName);
881
        state.set("relationType", relationType);
882

    
883
        state.set("foreingKey", this.foreingKey);
884
        state.set("tags", this.tags);
885

    
886
        state.set("displaySize", displaySize);
887
        state.set("availableValuesExpression", availableValuesExpression);
888
        state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);
889
        state.set("defaultFormat", defaultFormat);
890
    }
891

    
892
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
893

    
894
    public static void registerPersistenceDefinition() {
895
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
896

    
897
        if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
898
                == null) {
899
            DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
900
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
901
                    FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
902
                    + " persistent definition",
903
                    null,
904
                    null
905
            );
906
            definition.addDynFieldBoolean("allowNull");
907
            definition.addDynFieldInt("dataType");
908
            definition.addDynFieldString("dataProfile");
909
//            definition.addDynFieldString("dateFormat");
910
            definition.addDynFieldString("defaultValue");
911
            definition.addDynFieldInt("index");
912
            definition.addDynFieldInt("maximumOccurrences");
913
            definition.addDynFieldInt("minimumOccurrences");
914
            definition.addDynFieldInt("size");
915
            definition.addDynFieldString("name");
916
            definition.addDynFieldString("objectClass");
917
            definition.addDynFieldInt("precision");
918
            definition.addDynFieldInt("scale").setMandatory(false).setDefaultDynValue(DataType.SCALE_NONE);
919
            definition.addDynFieldInt("roundMode").setMandatory(false).setDefaultDynValue(BigDecimal.ROUND_HALF_UP);
920
            definition.addDynFieldString("locale").setMandatory(false).setDefaultDynValue("null");
921
            definition.addDynFieldObject("evaluator").setClassOfValue(Evaluator.class);
922
            definition.addDynFieldBoolean("primaryKey");
923
            definition.addDynFieldBoolean("readOnly");
924
            definition.addDynFieldObject("SRS")
925
                    .setClassOfValue(IProjection.class);
926
            definition.addDynFieldInt("geometryType");
927
            definition.addDynFieldInt("geometrySubType");
928
//            definition.addDynFieldMap("additionalInfo");
929
            definition.addDynFieldBoolean("isAutomatic");
930
            definition.addDynFieldBoolean("isTime");
931
            definition.addDynFieldLong("interval_start");
932
            definition.addDynFieldLong("interval_end");
933
            definition.addDynFieldObject("featureAttributeEmulator")
934
                    .setClassOfValue(FeatureAttributeEmulator.class);
935
            definition.addDynFieldBoolean("indexed");
936
            definition.addDynFieldBoolean("isIndexAscending");
937
            definition.addDynFieldBoolean("allowIndexDuplicateds");
938
            definition.addDynFieldMap("availableValues")
939
                    .setClassOfItems(Object.class);
940
            definition.addDynFieldString("description");
941
            definition.addDynFieldObject("minValue");
942
            definition.addDynFieldObject("maxValue");
943
            definition.addDynFieldString("label");
944
            definition.addDynFieldInt("order");
945
            definition.addDynFieldBoolean("hidden");
946
            definition.addDynFieldBoolean("avoidCachingAvailableValues");
947
            definition.addDynFieldString("groupName");
948
            definition.addDynFieldInt("relationType");
949

    
950
            definition.addDynFieldObject("foreingKey")
951
                    .setClassOfValue(DefaultForeingKey.class);
952

    
953
            definition.addDynFieldObject("tags")
954
                    .setClassOfValue(Tags.class);
955

    
956
            definition.addDynFieldInt("displaySize").setMandatory(false);
957
            definition.addDynFieldObject("availableValuesExpression")
958
                    .setClassOfValue(Expression.class)
959
                    .setMandatory(false);
960
            definition.addDynFieldString("defaultFormat").setMandatory(false);
961
        }
962
    }
963

    
964
    /*
965
     * Start of DynField interface Implementation
966
     *
967
     */
968
    @Override
969
    public Tags getTags() {
970
        return tags;
971
    }
972

    
973
    private Expression availableValuesFilter;
974

    
975
    @Override
976
    public Expression getAvailableValuesFilter() {
977
        return this.availableValuesFilter;
978
    }
979

    
980
    public FeatureAttributeDescriptor setAvailableValuesFilter(Expression filter) {
981
        this.availableValuesFilter = filter;
982
        return this;
983
    }
984

    
985
    public FeatureAttributeDescriptor setAvailableValuesFilter(String filter) {
986
        this.availableValuesFilter = ExpressionUtils.createExpression(filter);
987
        return this;
988
    }
989

    
990
    @Override
991
    public boolean hasConstantAvailableValues() {
992
        return this.availableValues != null;
993
    }
994

    
995
    @Override
996
    public boolean isAvoidCachingAvailableValues() {
997
        return this.avoidCachingAvailableValues;
998
    }
999

    
1000
    public boolean hasAvailableValues() {
1001
        return getAvailableValues() != null;
1002
    }
1003

    
1004
    @Override
1005
    public DynObjectValueItem[] getAvailableValues(DynObject context) {
1006
        if (this.availableValuesMethod != null) {
1007
            DynObjectValueItem[] values;
1008
            try {
1009
                values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(context, new Object[]{this});
1010
            } catch (DynMethodException ex) {
1011
                return this.getAvailableValues();
1012
            }
1013
            if (values != null) {
1014
                return values;
1015
            }
1016
        }
1017
        Expression filter = this.availableValuesFilter;
1018
        if (!ExpressionUtils.isEmpty(filter)) {
1019
            if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1020
                ContextForeingKey foreingkeyContext = this.foreingKey.createContext();
1021
                foreingkeyContext.setContextValues(context);
1022
                DynObjectValueItem[] values = this.foreingKey.getAvailableValues(foreingkeyContext);
1023
                return values;
1024
            }
1025
            MutableSymbolTable contextSymbolTable = ExpressionUtils.createSymbolTable("feature", context);
1026
            MutableSymbolTable symbolTable = ExpressionUtils.createSymbolTable();
1027
            symbolTable.addSymbolTable(contextSymbolTable);
1028

    
1029
            DynObjectValueItem[] allValues = this.getAvailableValues();
1030
            List<DynObjectValueItem> filteredValues = new ArrayList<>();
1031
            for (DynObjectValueItem value : allValues) {
1032
                symbolTable.setVar("$value", value.getValue());
1033
                symbolTable.setVar("$label", value.getLabel());
1034
                Object include = filter.execute(symbolTable);
1035
                if (DataTypeUtils.isFalse(include, false)) {
1036
                    continue;
1037
                }
1038
                filteredValues.add(value);
1039
            }
1040
            DynObjectValueItem[] values = filteredValues.toArray(
1041
                    new DynObjectValueItem[filteredValues.size()]
1042
            );
1043
            return values;
1044
        }
1045
        return this.getAvailableValues();
1046
    }
1047

    
1048
    @Override
1049
    public boolean isAvailableValuesCalculated() {
1050
        if (this.availableValuesMethod != null) {
1051
            return true;
1052
        }
1053
        if (!ExpressionUtils.isEmpty(this.availableValuesFilter)) {
1054
            return true;
1055
        }
1056
        if( this.isForeingKey() && this.foreingKey.isClosedList() ) {
1057
            return true;
1058
        }
1059
        return false;
1060
    }
1061

    
1062
    @Override
1063
    public DynObjectValueItem[] getAvailableValues() {
1064
        DynObjectValueItem[] values = this.availableValues;
1065

    
1066
        if (values != null) {
1067
            return values;
1068
        }
1069
        if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1070
            values = this.foreingKey.getAvailableValues(null);
1071
            return values;
1072
        }
1073
        values = this.availableValuesCache;
1074
        if (values != null) {
1075
            return values;
1076
        }
1077
//        if (this.isForeingKey() && this.foreingKey.isClosedList()) {
1078
//            values = this.foreingKey.getAvailableValues(null);
1079
//
1080
//        } else 
1081
        if (this.availableValuesExpression != null) {
1082
            values = this.getAvailableValuesFromExpression();
1083
        }
1084
        if (!this.avoidCachingAvailableValues) {
1085
            this.availableValuesCache = values;
1086
        }
1087
        return values;
1088
    }
1089

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

    
1224
    private DynObjectValueItem[] getAvailableValuesFromExpression() {
1225
        if (this.availableValuesExpression == null || this.availableValuesExpression.isEmpty()) {
1226
            return null;
1227
        }
1228
        try {
1229
            Object value = this.availableValuesExpression.execute(null);
1230
            if (value instanceof DynObjectValueItem[]) {
1231
                return (DynObjectValueItem[]) value;
1232
            }
1233
            if (value instanceof List) {
1234
                return this.getAvailableValuesFrom(new GetItemWithSize() {
1235
                    @Override
1236
                    public Object get(int i) {
1237
                        return ((List) value).get(i);
1238
                    }
1239

    
1240
                    @Override
1241
                    public int size() {
1242
                        return ((List) value).size();
1243
                    }
1244
                });
1245
            }
1246
        } catch (Throwable th) {
1247
            LOGGER.warn("Can't get available values from expression", th);
1248
        }
1249
        return null;
1250
    }
1251

    
1252
    @Override
1253
    public Expression getAvailableValuesExpression() {
1254
        return this.availableValuesExpression;
1255
    }
1256

    
1257
    @Override
1258
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1259
        if (StringUtils.isBlank(expression)) {
1260
            this.availableValuesExpression = null;
1261
            return this;
1262
        }
1263
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1264
        return this;
1265
    }
1266

    
1267
    @Override
1268
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1269
        this.availableValuesExpression = expression;
1270
        return this;
1271
    }
1272

    
1273
    @Override
1274
    public String getLabelOfValue(Object value) {
1275
        String theLabel = null;
1276
        if( this.isForeingKey() && !this.getForeingKey().isClosedList() ) {
1277
            theLabel = this.getForeingKey().getLabel(null, value);
1278
            if( StringUtils.isNotBlank(theLabel) ) {
1279
                return theLabel;
1280
            }
1281
        }
1282
        if (this.labelOfValueMap != null) {
1283
            theLabel = this.labelOfValueMap.get(value);
1284
            if (theLabel == null) {
1285
                theLabel = Objects.toString(value, "");
1286
            }
1287
            return theLabel;
1288
        }
1289
        DynObjectValueItem[] values = this.getAvailableValues();
1290
        if (values == null) {
1291
            return this.format(value);
1292
        }
1293
        Map<Object, String> map = new LinkedHashMap<>();
1294
        for (DynObjectValueItem theValue : values) {
1295
            map.put(theValue.getValue(), theValue.getLabel());
1296
        }
1297
        this.labelOfValueMap = map;
1298
        theLabel = this.labelOfValueMap.get(value);
1299
        if (theLabel == null) {
1300
            return this.format(value);
1301
        }
1302
        return theLabel;
1303
    }
1304

    
1305
    @Override
1306
    public String getDescription() {
1307
        if (this.description == null) {
1308
            return getName();
1309
        }
1310
        return this.description;
1311
    }
1312

    
1313
    @Override
1314
    public Object getMaxValue() {
1315
        return this.maxValue;
1316
    }
1317

    
1318
    @Override
1319
    public Object getMinValue() {
1320
        return this.minValue;
1321
    }
1322

    
1323
    @Override
1324
    public int getTheTypeOfAvailableValues() {
1325
        return 1;
1326
    }
1327

    
1328
    @Override
1329
    public int getType() {
1330
        if (featureAttributeGetter != null) {
1331
            return featureAttributeGetter.getDataType().getType();
1332
        }
1333
        return getDataType().getType();
1334
    }
1335

    
1336
    @Override
1337
    public boolean isMandatory() {
1338
        return !allowNull() || isPrimaryKey();
1339
    }
1340

    
1341
    @Override
1342
    public boolean isPersistent() {
1343
        return false;
1344
    }
1345

    
1346
    @Override
1347
    public DynField setAvailableValues(DynObjectValueItem[] values) {
1348
        if (ArrayUtils.isEmpty(values)) {
1349
            this.availableValues = null;
1350
        } else {
1351
            Coercion coercion = this.getCoercion();
1352
            this.availableValues = new DynObjectValueItem[values.length];
1353
            for (int i = 0; i < values.length; i++) {
1354
                DynObjectValueItem element = values[i];
1355
                Object value;
1356
                try {
1357
                    value = coercion.coerce(element.getValue());
1358
                } catch (CoercionException ex) {
1359
                    value = element.getValue();
1360
                }
1361
                this.availableValues[i] = new DynObjectValueItem(value, element.getLabel());
1362
            }
1363
        }
1364
        return this;
1365
    }
1366

    
1367
    @Override
1368
    public DynField setDescription(String description) {
1369
        this.description = description;
1370
        return this;
1371
    }
1372

    
1373
    @Override
1374
    public DynField setMandatory(boolean mandatory) {
1375
        throw new UnsupportedOperationException();
1376
    }
1377

    
1378
    @Override
1379
    public DynField setMaxValue(Object maxValue) {
1380
        try {
1381
            this.maxValue = this.coerce(maxValue);
1382
        } catch (CoercionException e) {
1383
            throw new IllegalArgumentException(e);
1384
        }
1385
        return this;
1386
    }
1387

    
1388
    @Override
1389
    public DynField setMinValue(Object minValue) {
1390
        try {
1391
            this.maxValue = this.coerce(minValue);
1392
        } catch (CoercionException e) {
1393
            throw new IllegalArgumentException(e);
1394
        }
1395
        return this;
1396
    }
1397

    
1398
    @Override
1399
    public DynField setPersistent(boolean persistent) {
1400
        throw new UnsupportedOperationException();
1401
    }
1402

    
1403
    @Override
1404
    public DynField setTheTypeOfAvailableValues(int type) {
1405
        throw new UnsupportedOperationException();
1406
    }
1407

    
1408
    @Override
1409
    public DynField setType(int type) {
1410
        throw new UnsupportedOperationException();
1411
    }
1412

    
1413
    @Override
1414
    @Deprecated
1415
    public DynField setDefaultDynValue(Object defaultValue) {
1416
        return this.setDefaultFieldValue(defaultValue);
1417
    }
1418

    
1419
    @Override
1420
    public DynField setDefaultFieldValue(Object defaultValue) {
1421
        this.defaultValue = defaultValue;
1422
        return this;
1423
    }
1424

    
1425
    @Override
1426
    public Class getClassOfValue() {
1427
        return null;
1428
    }
1429

    
1430
    @Override
1431
    public DynField getElementsType() {
1432
        return null;
1433
    }
1434

    
1435
    @Override
1436
    public DynField setClassOfValue(Class theClass)
1437
            throws DynFieldIsNotAContainerException {
1438
        throw new UnsupportedOperationException();
1439
    }
1440

    
1441
    @Override
1442
    public DynField setElementsType(DynStruct type)
1443
            throws DynFieldIsNotAContainerException {
1444
        throw new UnsupportedOperationException();
1445
    }
1446

    
1447
    @Override
1448
    public DynField setElementsType(int type)
1449
            throws DynFieldIsNotAContainerException {
1450
        throw new UnsupportedOperationException();
1451
    }
1452

    
1453
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1454
        this.dataProfile = dataProfile;
1455
        return this;
1456
    }
1457

    
1458
    @Override
1459
    public String getDataProfileName() {
1460
        return dataProfile;
1461
    }
1462

    
1463
    @Override
1464
    public boolean hasDataProfile() {
1465
        return StringUtils.isNotBlank(dataProfile);
1466
    }
1467
    
1468
    @Override
1469
    public DataProfile getDataProfile() {
1470
        if (StringUtils.isBlank(dataProfile)) {
1471
            return null;
1472
        }
1473
        DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1474
        return profile;
1475
    }
1476

    
1477
    @Override
1478
    public void validate(Object value) throws DynFieldValidateException {
1479

    
1480
        if (value == null && !this.allowNull()) {
1481
            throw new DynFieldValidateException(value, this, null);
1482
        }
1483

    
1484
        try {
1485
            this.dataType.coerce(value);
1486
        } catch (CoercionException e) {
1487
            throw new DynFieldValidateException(value, this, e);
1488
        }
1489

    
1490
        /*
1491
         * Other checks will be needed
1492
         */
1493
    }
1494

    
1495
    @Override
1496
    public String getSubtype() {
1497
        if (featureAttributeGetter != null) {
1498
            return featureAttributeGetter.getDataType().getSubtype();
1499
        }
1500
        return this.dataType.getSubtype();
1501
    }
1502

    
1503
    @Override
1504
    public Object coerce(Object value) throws CoercionException {
1505
        if (value == null) {
1506
            return value; // O debe devolver this.defaultValue
1507
        }
1508
        try {
1509
            return this.getDataType().coerce(value, this.getCoercionContext());
1510
        } catch (Exception ex) {
1511
            throw new RuntimeException(ex);
1512
        }
1513
    }
1514

    
1515
    @Override
1516
    public DynField setAvailableValues(List values) {
1517
        if (values == null || values.isEmpty()) {
1518
            this.availableValues = null;
1519
        } else {
1520
            this.availableValues = (DynObjectValueItem[]) values.toArray(
1521
                    new DynObjectValueItem[values.size()]
1522
            );
1523
        }
1524
        return this;
1525
    }
1526

    
1527
    @Override
1528
    public String getGroup() {
1529
        return this.groupName;
1530
    }
1531

    
1532
    @Override
1533
    public int getOder() {
1534
        return this.order;
1535
    }
1536

    
1537
    @Override
1538
    public String getLabel() {
1539
        if (this.label == null) {
1540
            return this.getName();
1541
        }
1542
        return this.label;
1543
    }
1544

    
1545
    @Override
1546
    public String getLocalizedLabel() {
1547
        if (StringUtils.isBlank(this.label)) {
1548
            return this.getName();
1549
        }
1550
        I18nManager i18n = ToolsLocator.getI18nManager();
1551
        return i18n.getTranslation(this.label);
1552
    }
1553

    
1554
    @Override
1555
    public DynField setLabel(String label) {
1556
        this.label = label;
1557
        return this;
1558
    }
1559

    
1560
    @Override
1561
    public DynField setShortLabel(String shortLabel) {
1562
        this.shortLabel = shortLabel;
1563
        return this;
1564
    }
1565

    
1566
    @Override
1567
    public String getShortLabel() {
1568
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1569
    }
1570

    
1571
    @Override
1572
    public String getLocalizedShortLabel() {
1573
        if (StringUtils.isBlank(shortLabel)) {
1574
            return this.getLocalizedLabel();
1575
        }
1576
        I18nManager i18n = ToolsLocator.getI18nManager();
1577
        return i18n.getTranslation(shortLabel);
1578
    }
1579

    
1580
    @Override
1581
    public DynField setGroup(String groupName) {
1582
        this.groupName = groupName;
1583
        return this;
1584
    }
1585

    
1586
    @Override
1587
    public DynField setOrder(int order) {
1588
        this.order = order;
1589
        return this;
1590
    }
1591

    
1592
    @Override
1593
    public DynField setHidden(boolean hidden) {
1594
        this.hidden = hidden;
1595
        return this;
1596
    }
1597

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

    
1603
    @Override
1604
    public DynField setReadOnly(boolean readOnly) {
1605
        this.readOnly = readOnly;
1606
        return this;
1607
    }
1608

    
1609
    @Override
1610
    public boolean isContainer() {
1611
        return false;
1612
    }
1613

    
1614
    @Override
1615
    public Class getClassOfItems() {
1616
        return null;
1617
    }
1618

    
1619
    @Override
1620
    public DynField setClassOfItems(Class theClass) {
1621
        throw new UnsupportedOperationException();
1622
    }
1623

    
1624
    @Override
1625
    public DynField setType(DataType type) {
1626
        throw new UnsupportedOperationException();
1627
    }
1628

    
1629
    @Override
1630
    public DynField setSubtype(String subtype) {
1631
        throw new UnsupportedOperationException();
1632
    }
1633

    
1634
    @Override
1635
    public boolean isTime() {
1636
        return isTime;
1637
    }
1638

    
1639
    @Override
1640
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1641
        return featureAttributeGetter;
1642
    }
1643

    
1644
    @Override
1645
    public void setFeatureAttributeGetter(
1646
            FeatureAttributeGetter featureAttributeTransform) {
1647
        this.featureAttributeGetter = featureAttributeTransform;
1648
    }
1649

    
1650
    @Override
1651
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1652
        return this.featureAttributeEmulator;
1653
    }
1654

    
1655
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1656
        this.featureAttributeEmulator = featureAttributeEmulator;
1657
        return this;
1658
    }
1659

    
1660
    @Override
1661
    public boolean isIndexed() {
1662
        return this.indexed;
1663
    }
1664

    
1665
    @Override
1666
    public boolean isForeingKey() {
1667
        return this.foreingKey != null && this.foreingKey.isForeingKey();
1668
    }
1669

    
1670
    @Override
1671
    public ForeingKey getForeingKey() {
1672
        return this.foreingKey;
1673
    }
1674

    
1675
    @Override
1676
    public boolean allowIndexDuplicateds() {
1677
        return this.allowIndexDuplicateds;
1678
    }
1679

    
1680
    @Override
1681
    public boolean isIndexAscending() {
1682
        return this.isIndexAscending;
1683
    }
1684

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

    
1690
    @Override
1691
    public DynField setClassOfValue(String theClassNameOfValue) {
1692
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1693
    }
1694

    
1695
    @Override
1696
    public String getClassNameOfValue() {
1697
        return null;
1698
    }
1699

    
1700
    @Override
1701
    public DynStruct getDynClassOfValue() {
1702
        return null;
1703
    }
1704

    
1705
    @Override
1706
    public DynField setTypeOfItems(int type) {
1707
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1708
    }
1709

    
1710
    @Override
1711
    public int getTypeOfItems() {
1712
        return DataTypes.INVALID;
1713
    }
1714

    
1715
    @Override
1716
    public DynField setClassOfItems(DynStruct dynStrct) {
1717
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1718
    }
1719

    
1720
    @Override
1721
    public DynField setClassOfItems(String theClassNameOfValue) {
1722
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1723
    }
1724

    
1725
    @Override
1726
    public String getClassNameOfItems() {
1727
        return null;
1728
    }
1729

    
1730
    @Override
1731
    public DynStruct getDynClassOfItems() {
1732
        return null;
1733
    }
1734

    
1735
    @Override
1736
    public DynField setRelationType(int relationType) {
1737
        this.relationType = relationType;
1738
        return this;
1739
    }
1740

    
1741
    @Override
1742
    public int getRelationType() {
1743
        return this.relationType;
1744
    }
1745

    
1746
    @Override
1747
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1748
        this.availableValuesMethod = availableValuesMethod;
1749
        return this;
1750
    }
1751

    
1752
    @Override
1753
    public DynMethod getAvailableValuesMethod() {
1754
        if (this.availableValuesMethod != null) {
1755
            return this.availableValuesMethod;
1756
        }
1757
        if (this.availableValuesFilter == null && !this.isForeingKey()) {
1758
            return null;
1759
        }
1760
        DynMethod method = new AbstractDynMethod("getAvailableValuesOf" + this.getName()) {
1761
            @Override
1762
            public Object invoke(DynObject context, Object[] args) throws DynMethodException {
1763
                return getAvailableValues(context);
1764
            }
1765
        };
1766
        return method;
1767
    }
1768

    
1769
    @Override
1770
    public DynMethod getCalculateMethod() {
1771
        return this.calculateMethod;
1772
    }
1773

    
1774
    @Override
1775
    public DynField setCalculateMethod(DynMethod method) {
1776
        this.calculateMethod = method;
1777
        return this;
1778
    }
1779

    
1780
    @Override
1781
    public boolean isCalculated() {
1782
        return this.calculateMethod != null;
1783
    }
1784

    
1785
    @Override
1786
    public Object getCalculatedValue(DynObject self) {
1787
        try {
1788
            return this.calculateMethod.invoke(self, new Object[]{this});
1789
        } catch (DynMethodException ex) {
1790
            throw new RuntimeException(ex);
1791
        }
1792
    }
1793

    
1794
    @Override
1795
    public DynField setValidateElements(boolean validate) {
1796
        return this;
1797
    }
1798

    
1799
    @Override
1800
    public boolean getValidateElements() {
1801
        return false;
1802
    }
1803

    
1804
    @Override
1805
    public boolean hasLabel() {
1806
        return StringUtils.isNotBlank(this.label);
1807
    }
1808

    
1809
    @Override
1810
    public boolean hasShortLabel() {
1811
        return StringUtils.isNotBlank(this.shortLabel);
1812
    }
1813

    
1814
    @Override
1815
    public boolean hasDescription() {
1816
        return StringUtils.isNotBlank(this.description);
1817
    }
1818

    
1819
    @Override
1820
    public FeatureAttributeDescriptor getValue() {
1821
        return this;
1822
    }
1823

    
1824
    @Override
1825
    public int getDisplaySize() {
1826
        return this.displaySize;
1827
    }
1828

    
1829
    @Override
1830
    public boolean isInAvailableValues(Object valueToCheck) {
1831
        if (this.getAvailableValues() != null) {
1832
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1833
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1834
                    return true;
1835
                }
1836
            }
1837
        }
1838
        return false;
1839
    }
1840

    
1841
    private class ConstantValueEvaluator extends AbstractEvaluator {
1842

    
1843
        @Override
1844
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1845
            return defaultValue;
1846
        }
1847

    
1848
        @Override
1849
        public String getName() {
1850
            return "Constant attribute " + name;
1851
        }
1852
    }
1853

    
1854
    public void setConstantValue(boolean isConstantValue) {
1855
        if (isConstantValue) {
1856
            /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1857
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1858
             * el evaluador el que se encarga de proporcionar su valor.
1859
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1860
             * por defecto para ese attributo.
1861
             */
1862
            this.evaluator = new ConstantValueEvaluator();
1863
        } else {
1864
            this.evaluator = null;
1865
        }
1866
    }
1867

    
1868
    @Override
1869
    public boolean isComputed() {
1870
        return featureAttributeEmulator != null || evaluator != null || isCalculated();
1871
    }
1872

    
1873
    @Override
1874
    public FeatureStore getStore() {
1875
        FeatureType ftype = this.getFeatureType();
1876
        if (ftype == null) {
1877
            return null;
1878
        }
1879
        return ftype.getStore();
1880
    }
1881

    
1882
    @Override
1883
    public FeatureType getFeatureType() {
1884
        if (this.typeRef == null) {
1885
            return null;
1886
        }
1887
        FeatureType ftype = (FeatureType) this.typeRef.get();
1888
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1889
        return ftype;
1890
    }
1891

    
1892
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1893
        this.interval = interval;
1894
        return this;
1895
    }
1896

    
1897
    public void fixAll() {
1898
        if (!this.getDataType().supportSize()) {
1899
            this.size = 0;
1900
        }
1901
        NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1902
        this.precision = ps.getPrecision();
1903
        this.scale = ps.getScale();
1904

    
1905
        switch (this.getType()) {
1906
            case DataTypes.INSTANT:
1907
            case DataTypes.INTERVAL:
1908
            case DataTypes.DATE:
1909
            case DataTypes.TIME:
1910
            case DataTypes.TIMESTAMP:
1911
                if (this.getInterval() != null) {
1912
                    this.isTime = true;
1913
                }
1914
                break;
1915
        }
1916
//        TODO: Habria que meter este cambio en proximos builds 2022/11/16.
1917
//        if( this.isPrimaryKey() ) {
1918
//            this.allowNull = false;
1919
//        }
1920
        
1921
    }
1922

    
1923
    @Override
1924
    public String[] getRequiredFieldNames() {
1925
        FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1926
        if (emulator == null) {
1927
            return null;
1928
        }
1929
        return emulator.getRequiredFieldNames();
1930
    }
1931

    
1932
    @Override
1933
    public void recentUsed() {
1934
        DefaultFeatureType.RECENTS_USEDS.add(this);
1935
    }
1936

    
1937
    @Override
1938
    public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1939
        if (other == null) {
1940
            throw new NullPointerException();
1941
        }
1942
        DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1943
        if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1944
            return false;
1945
        }
1946
        if (old.isComputed() && old.isComputed() == this.isComputed()) {
1947
            return true;
1948
        }
1949
        if (this.dataType != old.dataType) {
1950
            return false;
1951
        }
1952
        if (this.size != old.size) {
1953
            return false;
1954
        }
1955
        if (this.precision != old.precision) {
1956
            return false;
1957
        }
1958
//        if( this.primaryKey != old.primaryKey ) {
1959
//            return false;
1960
//        }
1961
        if (this.geomType != old.geomType) {
1962
            return false;
1963
        }
1964
        if (this.SRS != old.SRS) {
1965
            return false;
1966
        }
1967
        if (this.isAutomatic != old.isAutomatic) {
1968
            return false;
1969
        }
1970
        return true;
1971
    }
1972

    
1973
    private class PropertiesBuilder {
1974

    
1975
        private String name;
1976
        private DataType type;
1977
        private Map<String, String> sets;
1978
        private Map<String, String> tags;
1979
        private String sep;
1980

    
1981
        public PropertiesBuilder() {
1982
            this.sets = new LinkedHashMap<>();
1983
        }
1984

    
1985
        public void separator(String sep) {
1986
            this.sep = sep;
1987
        }
1988

    
1989
        public void name(String name) {
1990
            this.name = name;
1991
        }
1992

    
1993
        public void type(DataType type) {
1994
            this.type = type;
1995
        }
1996

    
1997
        public void set(String name, ForeingKey fk) {
1998
            if (fk == null) {
1999
                return;
2000
            }
2001
            if (!fk.isForeingKey()) {
2002
                return;
2003
            }
2004
            this.set(name, fk.isForeingKey());
2005
            this.set(name + "_code", fk.getCodeName());
2006
            this.set(name + "_label", fk.getLabelFormula());
2007
            this.set(name + "_closedlist", fk.isClosedList());
2008
            this.set(name + "_table", fk.getTableName());
2009
        }
2010

    
2011
        public void set(String name, FeatureAttributeEmulator value) {
2012
            if (value == null) {
2013
                return;
2014
            }
2015
            if (value instanceof FeatureAttributeEmulatorExpression) {
2016
                this.set(name, ((FeatureAttributeEmulatorExpression) value).getExpression().getPhrase());
2017
            }
2018
        }
2019

    
2020
        public void set(String name, IProjection value) {
2021
            if (value == null) {
2022
                return;
2023
            }
2024
            this.set(name, value.getAbrev());
2025
        }
2026

    
2027
        public void set(String name, GeometryType value) {
2028
            if (value == null) {
2029
                return;
2030
            }
2031
            this.set(name, value.getFullName().replace(":", "@"));
2032
        }
2033

    
2034
        public void set(String name, Object value) {
2035
            if (value == null) {
2036
                return;
2037
            }
2038
            String s = Objects.toString(value, "");
2039
            if (StringUtils.isBlank(s)) {
2040
                return;
2041
            }
2042
            this.sets.put(name, s);
2043
        }
2044

    
2045
        public void set(String name, Object value, Object skipValue) {
2046
            if (value == null || value == skipValue) {
2047
                return;
2048
            }
2049
            String s = Objects.toString(value, "");
2050
            if (StringUtils.isBlank(s)) {
2051
                return;
2052
            }
2053
            this.sets.put(name, s);
2054
        }
2055

    
2056
        public void tag(String name, String value) {
2057
            if (value == null) {
2058
                return;
2059
            }
2060
            if (StringUtils.isBlank(value)) {
2061
                return;
2062
            }
2063
            if( this.tags == null ) {
2064
                this.tags = new HashMap<>();
2065
            }
2066
            this.tags.put(name, value);
2067
        }
2068

    
2069
        @Override
2070
        public String toString() {
2071
            StringBuilder builder = new StringBuilder();
2072
            builder.append(this.name);
2073
            builder.append(sep);
2074
            builder.append(this.type.getName());
2075
            for (String key : this.sets.keySet()) {
2076
                builder.append(sep);
2077
                builder.append("set");
2078
                builder.append(sep);
2079
                builder.append(key);
2080
                builder.append("=");
2081
                builder.append(this.sets.get(key));
2082
            }
2083
            if( this.tags!=null ) {
2084
                for (String key : this.tags.keySet()) {
2085
                    builder.append(sep);
2086
                    builder.append("tag");
2087
                    builder.append(sep);
2088
                    builder.append(key);
2089
                    builder.append("=");
2090
                    builder.append(this.tags.get(key));
2091
                }
2092
            }
2093
            return builder.toString();
2094
        }
2095
    }
2096

    
2097
    private String getAll() {
2098
        PropertiesBuilder builder = new PropertiesBuilder();
2099
        builder.separator("/");
2100
        builder.name(this.name);
2101
        builder.type(this.dataType);
2102
        builder.set("size", this.size, 0);
2103
        switch (this.getType()) {
2104
            case DataTypes.BYTE:
2105
            case DataTypes.INTEGER:
2106
            case DataTypes.LONG:
2107
                break;
2108
            case DataTypes.FLOAT:
2109
            case DataTypes.DOUBLE:
2110
                if(this.locale != null){
2111
                    builder.set("locale", this.getLocale());
2112
                }
2113
                break;
2114
            case DataTypes.DECIMAL:
2115
                builder.set("precision", this.precision);
2116
                builder.set("scale", this.scale);
2117
                builder.set("roundMode", this.getRoundMode());
2118
                if(this.locale != null){
2119
                    builder.set("locale", this.getLocale());
2120
                }
2121
                break;
2122
            case DataTypes.DATE:
2123
            case DataTypes.TIME:
2124
            case DataTypes.TIMESTAMP:
2125
                if(this.locale != null){
2126
                    builder.set("locale", this.getLocale());
2127
                }
2128
                break;
2129
            case DataTypes.GEOMETRY:
2130
                IProjection proj = this.getSRS();
2131
                if (proj != null) {
2132
                    builder.set("srs", proj.getAbrev().replace(":", "@"));
2133
                }
2134
                GeometryType theGeomType = this.getGeomType();
2135
                if (theGeomType != null) {
2136
                    String geomTypeName = GeometryUtils.getGeometryTypeName(this.getGeomType().getType());
2137
                    String geomSubtypeName = GeometryUtils.getGeometrySubtypeName(this.getGeomType().getSubType());
2138
                    builder.set("geomtype", geomTypeName + "@" + geomSubtypeName);
2139
                }
2140
                break;
2141
        }
2142
        builder.set("hidden", this.isHidden(), false);
2143
        builder.set("readOnly", this.isReadOnly(), false);
2144
        builder.set("allowNull", this.allowNull(), true);
2145
        builder.set("pk", this.isPrimaryKey(), false);
2146
        builder.set("automatic", this.isAutomatic(), false);
2147
        builder.set("isindexed", this.isIndexed(), false);
2148
        builder.set("isindexascending", this.isIndexAscending(), false);
2149
        builder.set("allowindexduplicateds", this.allowIndexDuplicateds(), false);
2150
        builder.set("isTime", this.isTime(), false);
2151
        builder.set("profile", this.getDataProfileName());
2152
        builder.set("group", this.getGroup());
2153
        builder.set("description", this.description);
2154
        builder.set("label", this.label);
2155
        builder.set("shortLabel", this.shortLabel);
2156
        builder.set("defaultvalue", this.getDefaultValue());
2157
        builder.set("order", this.getOder());
2158
        if (this.getFeatureAttributeEmulator() instanceof FeatureAttributeEmulatorExpression) {
2159
            Expression exp = ((FeatureAttributeEmulatorExpression) this.getFeatureAttributeEmulator()).getExpression();
2160
            if (exp != null) {
2161
                builder.set("expression", exp.getPhrase());
2162
            }
2163
        }
2164
        builder.set("isAvoidCachingAvailableValues", this.isAvoidCachingAvailableValues(), false);
2165
        if (this.isForeingKey()) {
2166
            builder.set("fk", this.isForeingKey());
2167
            builder.set("fk_table", this.getForeingKey().getTableName());
2168
            builder.set("fk_code", this.getForeingKey().getCodeName());
2169
            builder.set("fk_label", this.getForeingKey().getLabelFormula());
2170
            builder.set("fk.closedlist", this.getForeingKey().isClosedList());
2171
        }
2172
        Tags theTags = this.getTags();
2173
        for (String tagname : theTags) {
2174
            String value = theTags.getString(tagname,null);
2175
            if( value!=null ) {
2176
                builder.tag(tagname, value);
2177
            }
2178
        }
2179
        return builder.toString();
2180
    }
2181

    
2182
    @Override
2183
    public Object get(String name) {
2184
        if (StringUtils.isBlank(name)) {
2185
            throw new IllegalArgumentException("Name can't be empty");
2186
        }
2187
        switch (name.trim().toLowerCase()) {
2188
            case "all":
2189
                return this.getAll();
2190
            case "isreadonly":
2191
            case "readonly":
2192
                return this.isReadOnly();
2193
            case "hidden":
2194
                return this.isHidden();
2195
            case "allownull":
2196
                return this.allowNull();
2197
            case "pk":
2198
            case "ispk":
2199
            case "primarykey":
2200
            case "isprimarykey":
2201
                return this.isPrimaryKey();
2202
            case "isindexed":
2203
                return this.isIndexed();
2204
            case "isindexascending":
2205
                return this.isIndexAscending();
2206
            case "allowindexduplicateds":
2207
                return this.allowIndexDuplicateds();
2208
            case "isautomatic":
2209
            case "automatic":
2210
                return this.isAutomatic();
2211
            case "time":
2212
            case "istime":
2213
                return this.isTime();
2214
            case "profile":
2215
                return this.getDataProfile();
2216
            case "group":
2217
                return this.getGroup();
2218
            case "description":
2219
                return this.getDescription();
2220
            case "label":
2221
                return this.getLabel();
2222
            case "shortlabel":
2223
                return this.getShortLabel();
2224
            case "isavoidcachingavailablevalues":
2225
            case "avoidcachingavailablevalues":
2226
            case "nocachingavailablevalues":
2227
                return this.isAvoidCachingAvailableValues();
2228
            case "expression":
2229
                return this.getFeatureAttributeEmulator();
2230
            case "size":
2231
                return this.getSize();
2232
            case "precision":
2233
                return this.getPrecision();
2234
            case "scale":
2235
                return this.getScale();
2236
            case "roundmode":
2237
                return this.getRoundMode();
2238
            case "locale":
2239
                return this.getLocale();
2240
            case "order":
2241
                return this.getOder();
2242
            case "isfk":
2243
            case "isforeingkey":
2244
                return this.isForeingKey();
2245
            case "fk":
2246
            case "foreingkey":
2247
                return this.getForeingKey();
2248
            case "fk_code":
2249
            case "foreingkey_code":
2250
            case "foreingkey.code":
2251
                return this.getForeingKey().getCodeName();
2252
            case "fk_label":
2253
            case "foreingkey_label":
2254
            case "foreingkey.label":
2255
                return this.getForeingKey().getLabelFormula();
2256
            case "fk.closedlist":
2257
            case "foreingkey_closedlist":
2258
            case "foreingkey.closedlist":
2259
                return this.getForeingKey().isClosedList();
2260
            case "fk_table":
2261
            case "foreingkey_table":
2262
            case "foreingkey.table":
2263
                return this.getForeingKey().getTableName();
2264
            case "interval":
2265
                return this.getInterval();
2266
            case "geomtype":
2267
            case "geometrytype":
2268
                return this.getGeomType();
2269
            case "srs":
2270
                return this.getSRS();
2271
            case "defaultvalue":
2272
                return this.getDefaultValue();
2273
            default:
2274
                throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
2275
        }
2276
    }
2277

    
2278
    public void setSRSForced(IProjection SRS) {
2279
        this.SRS = SRS;
2280
    }
2281

    
2282
    @Override
2283
    public JsonObject toJson() {
2284
        return this.toJsonBuilder().build();
2285
    }
2286

    
2287
    @Override
2288
    public JsonObjectBuilder toJsonBuilder() {
2289
        JsonObjectBuilder builder = Json.createObjectBuilder();
2290
        builder.add_class(this);
2291
        builder.add("name", this.name);
2292
        builder.add("description", this.description);
2293
        builder.add("label", this.label);
2294
        builder.add("shortLabel", this.shortLabel);
2295
        builder.add("order", this.order);
2296
        builder.add("groupName", this.groupName);
2297
        builder.add("dataType", this.dataType);
2298
        builder.add("size", this.size);
2299
        builder.add("precision", this.precision);
2300
        builder.add("scale", this.scale);
2301
        builder.add("roundMode", this.roundMode);
2302

    
2303
        builder.add("allowNull", this.allowNull);
2304
        builder.add("primaryKey", this.primaryKey);
2305
        builder.add("readOnly", this.readOnly);
2306
        builder.add("isAutomatic", this.isAutomatic);
2307
        builder.add("isTime", this.isTime);
2308
        builder.add("indexed", this.indexed);
2309
        builder.add("isIndexAscending", this.isIndexAscending);
2310
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2311
        builder.add("hidden", this.hidden);
2312
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2313

    
2314
        builder.add("geometryType", this.getGeomType());
2315
        builder.add("srs", this.getSRS());
2316

    
2317
        builder.add("relationType", this.relationType);
2318
        builder.add("displaySize", this.displaySize);
2319
        if(this.locale == null){ //!this.hasLocale()
2320
            builder.addNull("locale");
2321
        } else {
2322
            builder.add("locale", this.getLocale());
2323
        }
2324
        builder.add("expression", this.getFeatureAttributeEmulator());
2325
        if (this.isForeingKey()) {
2326
            builder.add("fk", this.isForeingKey());
2327
            builder.add("fk_table", this.getForeingKey().getTableName());
2328
            builder.add("fk_code", this.getForeingKey().getCodeName());
2329
            builder.add("fk_label", this.getForeingKey().getLabelFormula());
2330
            builder.add("fk_closedlist", this.getForeingKey().isClosedList());
2331
        }
2332
        builder.add("availableValuesExpression", this.availableValuesExpression);
2333
        builder.add("defaultValue", Objects.toString(this.defaultValue, null));
2334
        builder.add("dataProfile", this.getDataProfileName());
2335
        builder.add("tags", tags);
2336
        builder.add("availableValues", availableValues);
2337
        builder.add("additionalInfo", this.additionalInfo);
2338
        builder.add("defaultFormat", this.defaultFormat);
2339
        return builder;
2340
    }
2341

    
2342
    public void fromJson(JsonObject json) {
2343
        this.name = json.getString("name");
2344
        this.description = json.getString("description");
2345
        this.label = json.getString("label");
2346
        this.shortLabel = json.getString("shortLabel");
2347
        this.order = json.getInt("order");
2348
        this.groupName = json.getString("groupName");
2349
        this.precision = json.getInt("precision");
2350
        this.size = json.getInt("size");
2351
        this.scale = json.getInt("scale");
2352
        this.roundMode = json.getInt("roundMode");
2353

    
2354
        this.allowNull = json.getBoolean("allowNull");
2355
        this.primaryKey = json.getBoolean("primaryKey");
2356
        this.readOnly = json.getBoolean("readOnly");
2357
        this.isAutomatic = json.getBoolean("isAutomatic");
2358
        this.isTime = json.getBoolean("isTime");
2359
        this.indexed = json.getBoolean("indexed");
2360
        this.isIndexAscending = json.getBoolean("isIndexAscending");
2361
        this.allowIndexDuplicateds = json.getBoolean("allowIndexDuplicateds");
2362
        this.hidden = json.getBoolean("hidden");
2363
        this.avoidCachingAvailableValues = json.getBoolean("avoidCachingAvailableValues");
2364

    
2365
        this.relationType = json.getInt("relationType");
2366
        this.displaySize = json.getInt("displaySize");
2367

    
2368
        this.dataType = (DataType) Json.toObject(json, "dataType");
2369
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2370
        this.SRS = (IProjection) Json.toObject(json, "srs");
2371
        this.locale = (Locale) Json.toObject(json, "locale");
2372
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json, "expression");
2373

    
2374
        this.tags = (Tags) Json.toObject(json, "tags");
2375
        this.additionalInfo = Json.toMap(json, "additionalInfo");
2376
        this.availableValues = (DynObjectValueItem[]) Json.toArray(json, "availableValues", new DynObjectValueItem[0]);
2377
        this.dataProfile = json.getString("dataProfile", null);
2378
        try {
2379
            this.defaultValue = json.getString("defaultValue", null);
2380
            if(!(this.defaultValue instanceof String && ExpressionUtils.isDynamicText((String) this.defaultValue))){
2381
                this.defaultValue = this.coerce(this.defaultValue);
2382
            }
2383
        } catch (Exception ex) {
2384
            LOGGER.warn("Can't retrive default value for attribute '" + this.name + "'.", ex);
2385
        }
2386
        this.availableValuesExpression = (Expression) Json.toObject(json, "availableValuesExpression");
2387
        if (json.getBoolean("fk", false)) {
2388
            this.foreingKey = new DefaultForeingKey();
2389
            this.foreingKey.setForeingKey(true);
2390
            this.foreingKey.setTableName(json.getString("fk_table", null));
2391
            this.foreingKey.setCodeName(json.getString("fk_code", null));
2392
            this.foreingKey.setLabelFormula(json.getString("fk_label", null));
2393
            this.foreingKey.setClosedList(json.getBoolean("fk_closedlist", false));
2394
        } else {
2395
            this.foreingKey = null;
2396
        }
2397
        this.defaultFormat = json.getString("defaultFormat",null);
2398
    }
2399

    
2400
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2401

    
2402
        public TheJsonSerializer() {
2403
        }
2404

    
2405
        @Override
2406
        public Class getObjectClass() {
2407
            return DefaultFeatureAttributeDescriptor.class;
2408
        }
2409

    
2410
        @Override
2411
        public Object toObject(JsonObject json) {
2412
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2413
            o.fromJson(json);
2414
            return o;
2415
        }
2416

    
2417
        @Override
2418
        public JsonObjectBuilder toJsonBuilder(Object value) {
2419
            return ((SupportToJson) value).toJsonBuilder();
2420
        }
2421

    
2422
    }
2423

    
2424
    public static void selfRegister() {
2425
        Json.registerSerializer(new TheJsonSerializer());
2426
    }
2427

    
2428
    @Override
2429
    public String getDefaultFormat() {
2430
        return this.defaultFormat;
2431
    }
2432

    
2433
    @Override
2434
    public String format(Object value) {
2435
        if(value == null){
2436
            return "";
2437
        }
2438
        try {
2439
            if( StringUtils.isBlank(this.defaultFormat)) {
2440
                if( this.locale==null ) { // !this.hasLocale()
2441
                    return DataTypeUtils.toString(Locale.getDefault(), value, Objects.toString(value, ""));
2442
                } else {
2443
                    return DataTypeUtils.toString(this.locale, value, Objects.toString(value, ""));
2444
                }
2445
            }
2446
            return String.format(this.defaultFormat, value);
2447
        } catch(Exception ex) {
2448
            return Objects.toString(value, "");
2449
        }
2450
    }
2451

    
2452
    @Override
2453
    public String toString() {
2454
        try {
2455
            String s = this.getAll();
2456
            return s;
2457
        } catch(Exception ex) {
2458
            return super.toString();
2459
        }
2460
    }
2461

    
2462
    
2463
}