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

History | View | Annotate | Download (78 KB)

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

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

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

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

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

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

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

    
166
    private int relationType = RELATION_TYPE_NONE;
167
    protected Locale locale;
168
    protected int displaySize;
169
    
170
    protected String defaultFormat;
171

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

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

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

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

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

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

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

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

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

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

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

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

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

    
357
    public FeatureAttributeDescriptor setDataType(int type) {
358
        this.dataType = ToolsLocator.getDataTypesManager().get(type);
359
        return this;
360
    }
361

    
362
    @Override
363
    public DateFormat getDateFormat() {
364
        return this.dateFormat;
365
    }
366

    
367
    @Override
368
    public Object getDefaultValue() {
369
        return this.defaultValue;
370
    }
371

    
372
    @Override
373
    @Deprecated
374
    public Object getDefaultValueCoerced() {
375
        return getCoercedDefaultValue();
376
    }
377

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

    
394
    @Override
395
    public Supplier getDefaultValueSupplier() {
396
        return (Supplier) this::getDefaultValueCoerced;
397
    }
398

    
399
    @Override
400
    public DynField setDefaultValueSupplier(Supplier supplier) {
401
        //Do nothing
402
        return this;
403
    }
404

    
405
    @Override
406
    public Evaluator getEvaluator() {
407
        return this.evaluator;
408
    }
409

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

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

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

    
446
    @Override
447
    public int getIndex() {
448
        return this.index;
449
    }
450

    
451
    protected FeatureAttributeDescriptor setIndex(int index) {
452
        this.index = index;
453
        return this;
454
    }
455

    
456
    @Override
457
    public int getMaximumOccurrences() {
458
        return this.maximumOccurrences;
459
    }
460

    
461
    @Override
462
    public int getMinimumOccurrences() {
463
        return this.minimumOccurrences;
464
    }
465

    
466
    @Override
467
    public String getName() {
468
        return this.name;
469
    }
470

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

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

    
485
    @Override
486
    public int getPrecision() {
487
        return this.precision;
488
    }
489

    
490
    @Override
491
    public int getScale() {
492
        return this.scale;
493
    }
494

    
495
    @Override
496
    public Coercion getCoercion() {
497
        return this.getDataType().getCoercion();
498
    }
499

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

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

    
539
    @Override
540
    public int getRoundMode() {
541
        return this.roundMode;
542
    }
543

    
544
    @Override
545
    public IProjection getSRS() {
546
        return this.SRS;
547
    }
548

    
549
    @Override
550
    public Interval getInterval() {
551
        return this.interval;
552
    }
553

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

    
562
    @Override
563
    public int getSize() {
564
        return this.size;
565
    }
566

    
567
    @Override
568
    public boolean isPrimaryKey() {
569
        return this.primaryKey;
570
    }
571

    
572
    @Override
573
    public boolean isReadOnly() {
574
        if (this.readOnly) {
575
            return true;
576
        }
577
        return this.isComputed();
578
    }
579

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

    
588
    @Override
589
    public boolean isAutomatic() {
590
        return this.isAutomatic;
591
    }
592

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

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

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

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

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

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

    
624
        if (!Objects.equals(this.defaultValue, other.defaultValue)) {
625
            return false;
626
        }
627
        if (!Objects.equals(this.defaultFormat, other.defaultFormat)) {
628
            return false;
629
        }
630

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

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

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

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

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

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

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

    
659
        if (this.geometrySubType != other.geometrySubType) {
660
            return false;
661
        }
662

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

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

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

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

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

    
683
        if (!Objects.equals(this.dataProfile, other.dataProfile)) {
684
            return false;
685
        }
686

    
687
        return true;
688
    }
689

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

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

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

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

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

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

    
791
    @Override
792
    public void saveToState(PersistentState state) throws PersistenceException {
793
        Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
794

    
795
        state.set("allowNull", allowNull);
796
        state.set("dataType", dataType.getType());
797
        state.set("dataProfile", dataProfile);
798

    
799
//        FIXME: dateFormat;
800
        state.set("defaultValue", Objects.toString(defaultValue, null));
801

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

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

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

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

    
849
        state.set("indexed", indexed);
850
        state.set("isIndexAscending", isIndexAscending);
851
        state.set("allowIndexDuplicateds", allowIndexDuplicateds);
852

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

    
871
        state.set("foreingKey", this.foreingKey);
872
        state.set("tags", this.tags);
873

    
874
        state.set("displaySize", displaySize);
875
        state.set("availableValuesExpression", availableValuesExpression);
876
        state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);
877
        state.set("defaultFormat", defaultFormat);
878
    }
879

    
880
    private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
881

    
882
    public static void registerPersistenceDefinition() {
883
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
884

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

    
938
            definition.addDynFieldObject("foreingKey")
939
                    .setClassOfValue(DefaultForeingKey.class);
940

    
941
            definition.addDynFieldObject("tags")
942
                    .setClassOfValue(Tags.class);
943

    
944
            definition.addDynFieldInt("displaySize").setMandatory(false);
945
            definition.addDynFieldObject("availableValuesExpression")
946
                    .setClassOfValue(Expression.class)
947
                    .setMandatory(false);
948
            definition.addDynFieldString("defaultFormat").setMandatory(false);
949
        }
950
    }
951

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

    
961
    private Expression availableValuesFilter;
962

    
963
    @Override
964
    public Expression getAvailableValuesFilter() {
965
        return this.availableValuesFilter;
966
    }
967

    
968
    public FeatureAttributeDescriptor setAvailableValuesFilter(Expression filter) {
969
        this.availableValuesFilter = filter;
970
        return this;
971
    }
972

    
973
    public FeatureAttributeDescriptor setAvailableValuesFilter(String filter) {
974
        this.availableValuesFilter = ExpressionUtils.createExpression(filter);
975
        return this;
976
    }
977

    
978
    @Override
979
    public boolean hasConstantAvailableValues() {
980
        return this.availableValues != null;
981
    }
982

    
983
    @Override
984
    public boolean isAvoidCachingAvailableValues() {
985
        return this.avoidCachingAvailableValues;
986
    }
987

    
988
    public boolean hasAvailableValues() {
989
        return getAvailableValues() != null;
990
    }
991

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

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

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

    
1047
    @Override
1048
    public DynObjectValueItem[] getAvailableValues() {
1049
        DynObjectValueItem[] values = this.availableValues;
1050

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

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

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

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

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

    
1232
    @Override
1233
    public Expression getAvailableValuesExpression() {
1234
        return this.availableValuesExpression;
1235
    }
1236

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

    
1247
    @Override
1248
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1249
        this.availableValuesExpression = expression;
1250
        return this;
1251
    }
1252

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

    
1278
    @Override
1279
    public String getDescription() {
1280
        if (this.description == null) {
1281
            return getName();
1282
        }
1283
        return this.description;
1284
    }
1285

    
1286
    @Override
1287
    public Object getMaxValue() {
1288
        return this.maxValue;
1289
    }
1290

    
1291
    @Override
1292
    public Object getMinValue() {
1293
        return this.minValue;
1294
    }
1295

    
1296
    @Override
1297
    public int getTheTypeOfAvailableValues() {
1298
        return 1;
1299
    }
1300

    
1301
    @Override
1302
    public int getType() {
1303
        if (featureAttributeGetter != null) {
1304
            return featureAttributeGetter.getDataType().getType();
1305
        }
1306
        return getDataType().getType();
1307
    }
1308

    
1309
    @Override
1310
    public boolean isMandatory() {
1311
        return !allowNull() || isPrimaryKey();
1312
    }
1313

    
1314
    @Override
1315
    public boolean isPersistent() {
1316
        return false;
1317
    }
1318

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

    
1340
    @Override
1341
    public DynField setDescription(String description) {
1342
        this.description = description;
1343
        return this;
1344
    }
1345

    
1346
    @Override
1347
    public DynField setMandatory(boolean mandatory) {
1348
        throw new UnsupportedOperationException();
1349
    }
1350

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

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

    
1371
    @Override
1372
    public DynField setPersistent(boolean persistent) {
1373
        throw new UnsupportedOperationException();
1374
    }
1375

    
1376
    @Override
1377
    public DynField setTheTypeOfAvailableValues(int type) {
1378
        throw new UnsupportedOperationException();
1379
    }
1380

    
1381
    @Override
1382
    public DynField setType(int type) {
1383
        throw new UnsupportedOperationException();
1384
    }
1385

    
1386
    @Override
1387
    @Deprecated
1388
    public DynField setDefaultDynValue(Object defaultValue) {
1389
        return this.setDefaultFieldValue(defaultValue);
1390
    }
1391

    
1392
    @Override
1393
    public DynField setDefaultFieldValue(Object defaultValue) {
1394
        this.defaultValue = defaultValue;
1395
        return this;
1396
    }
1397

    
1398
    @Override
1399
    public Class getClassOfValue() {
1400
        return null;
1401
    }
1402

    
1403
    @Override
1404
    public DynField getElementsType() {
1405
        return null;
1406
    }
1407

    
1408
    @Override
1409
    public DynField setClassOfValue(Class theClass)
1410
            throws DynFieldIsNotAContainerException {
1411
        throw new UnsupportedOperationException();
1412
    }
1413

    
1414
    @Override
1415
    public DynField setElementsType(DynStruct type)
1416
            throws DynFieldIsNotAContainerException {
1417
        throw new UnsupportedOperationException();
1418
    }
1419

    
1420
    @Override
1421
    public DynField setElementsType(int type)
1422
            throws DynFieldIsNotAContainerException {
1423
        throw new UnsupportedOperationException();
1424
    }
1425

    
1426
    public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1427
        this.dataProfile = dataProfile;
1428
        return this;
1429
    }
1430

    
1431
    @Override
1432
    public String getDataProfileName() {
1433
        return dataProfile;
1434
    }
1435

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

    
1445
    @Override
1446
    public void validate(Object value) throws DynFieldValidateException {
1447

    
1448
        if (value == null && !this.allowNull()) {
1449
            throw new DynFieldValidateException(value, this, null);
1450
        }
1451

    
1452
        try {
1453
            this.dataType.coerce(value);
1454
        } catch (CoercionException e) {
1455
            throw new DynFieldValidateException(value, this, e);
1456
        }
1457

    
1458
        /*
1459
         * Other checks will be needed
1460
         */
1461
    }
1462

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

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

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

    
1495
    @Override
1496
    public String getGroup() {
1497
        return this.groupName;
1498
    }
1499

    
1500
    @Override
1501
    public int getOder() {
1502
        return this.order;
1503
    }
1504

    
1505
    @Override
1506
    public String getLabel() {
1507
        if (this.label == null) {
1508
            return this.getName();
1509
        }
1510
        return this.label;
1511
    }
1512

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

    
1522
    @Override
1523
    public DynField setLabel(String label) {
1524
        this.label = label;
1525
        return this;
1526
    }
1527

    
1528
    @Override
1529
    public DynField setShortLabel(String shortLabel) {
1530
        this.shortLabel = shortLabel;
1531
        return this;
1532
    }
1533

    
1534
    @Override
1535
    public String getShortLabel() {
1536
        return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1537
    }
1538

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

    
1548
    @Override
1549
    public DynField setGroup(String groupName) {
1550
        this.groupName = groupName;
1551
        return this;
1552
    }
1553

    
1554
    @Override
1555
    public DynField setOrder(int order) {
1556
        this.order = order;
1557
        return this;
1558
    }
1559

    
1560
    @Override
1561
    public DynField setHidden(boolean hidden) {
1562
        this.hidden = hidden;
1563
        return this;
1564
    }
1565

    
1566
    @Override
1567
    public boolean isHidden() {
1568
        return this.hidden;
1569
    }
1570

    
1571
    @Override
1572
    public DynField setReadOnly(boolean readOnly) {
1573
        this.readOnly = readOnly;
1574
        return this;
1575
    }
1576

    
1577
    @Override
1578
    public boolean isContainer() {
1579
        return false;
1580
    }
1581

    
1582
    @Override
1583
    public Class getClassOfItems() {
1584
        return null;
1585
    }
1586

    
1587
    @Override
1588
    public DynField setClassOfItems(Class theClass) {
1589
        throw new UnsupportedOperationException();
1590
    }
1591

    
1592
    @Override
1593
    public DynField setType(DataType type) {
1594
        throw new UnsupportedOperationException();
1595
    }
1596

    
1597
    @Override
1598
    public DynField setSubtype(String subtype) {
1599
        throw new UnsupportedOperationException();
1600
    }
1601

    
1602
    @Override
1603
    public boolean isTime() {
1604
        return isTime;
1605
    }
1606

    
1607
    @Override
1608
    public FeatureAttributeGetter getFeatureAttributeGetter() {
1609
        return featureAttributeGetter;
1610
    }
1611

    
1612
    @Override
1613
    public void setFeatureAttributeGetter(
1614
            FeatureAttributeGetter featureAttributeTransform) {
1615
        this.featureAttributeGetter = featureAttributeTransform;
1616
    }
1617

    
1618
    @Override
1619
    public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1620
        return this.featureAttributeEmulator;
1621
    }
1622

    
1623
    public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1624
        this.featureAttributeEmulator = featureAttributeEmulator;
1625
        return this;
1626
    }
1627

    
1628
    @Override
1629
    public boolean isIndexed() {
1630
        return this.indexed;
1631
    }
1632

    
1633
    @Override
1634
    public boolean isForeingKey() {
1635
        return this.foreingKey != null && this.foreingKey.isForeingKey();
1636
    }
1637

    
1638
    @Override
1639
    public ForeingKey getForeingKey() {
1640
        return this.foreingKey;
1641
    }
1642

    
1643
    @Override
1644
    public boolean allowIndexDuplicateds() {
1645
        return this.allowIndexDuplicateds;
1646
    }
1647

    
1648
    @Override
1649
    public boolean isIndexAscending() {
1650
        return this.isIndexAscending;
1651
    }
1652

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

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

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

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

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

    
1678
    @Override
1679
    public int getTypeOfItems() {
1680
        return DataTypes.INVALID;
1681
    }
1682

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

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

    
1693
    @Override
1694
    public String getClassNameOfItems() {
1695
        return null;
1696
    }
1697

    
1698
    @Override
1699
    public DynStruct getDynClassOfItems() {
1700
        return null;
1701
    }
1702

    
1703
    @Override
1704
    public DynField setRelationType(int relationType) {
1705
        this.relationType = relationType;
1706
        return this;
1707
    }
1708

    
1709
    @Override
1710
    public int getRelationType() {
1711
        return this.relationType;
1712
    }
1713

    
1714
    @Override
1715
    public DynField setAvailableValues(DynMethod availableValuesMethod) {
1716
        this.availableValuesMethod = availableValuesMethod;
1717
        return this;
1718
    }
1719

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

    
1737
    @Override
1738
    public DynMethod getCalculateMethod() {
1739
        return this.calculateMethod;
1740
    }
1741

    
1742
    @Override
1743
    public DynField setCalculateMethod(DynMethod method) {
1744
        this.calculateMethod = method;
1745
        return this;
1746
    }
1747

    
1748
    @Override
1749
    public boolean isCalculated() {
1750
        return this.calculateMethod != null;
1751
    }
1752

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

    
1762
    @Override
1763
    public DynField setValidateElements(boolean validate) {
1764
        return this;
1765
    }
1766

    
1767
    @Override
1768
    public boolean getValidateElements() {
1769
        return false;
1770
    }
1771

    
1772
    @Override
1773
    public boolean hasLabel() {
1774
        return StringUtils.isNotBlank(this.label);
1775
    }
1776

    
1777
    @Override
1778
    public boolean hasShortLabel() {
1779
        return StringUtils.isNotBlank(this.shortLabel);
1780
    }
1781

    
1782
    @Override
1783
    public boolean hasDescription() {
1784
        return StringUtils.isNotBlank(this.description);
1785
    }
1786

    
1787
    @Override
1788
    public FeatureAttributeDescriptor getValue() {
1789
        return this;
1790
    }
1791

    
1792
    @Override
1793
    public int getDisplaySize() {
1794
        return this.displaySize;
1795
    }
1796

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

    
1809
    private class ConstantValueEvaluator extends AbstractEvaluator {
1810

    
1811
        @Override
1812
        public Object evaluate(EvaluatorData data) throws EvaluatorException {
1813
            return defaultValue;
1814
        }
1815

    
1816
        @Override
1817
        public String getName() {
1818
            return "Constant attribute " + name;
1819
        }
1820
    }
1821

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

    
1836
    @Override
1837
    public boolean isComputed() {
1838
        return featureAttributeEmulator != null || evaluator != null || isCalculated();
1839
    }
1840

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

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

    
1860
    public FeatureAttributeDescriptor setInterval(Interval interval) {
1861
        this.interval = interval;
1862
        return this;
1863
    }
1864

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

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

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

    
1895
    @Override
1896
    public void recentUsed() {
1897
        DefaultFeatureType.RECENTS_USEDS.add(this);
1898
    }
1899

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

    
1936
    private class PropertiesBuilder {
1937

    
1938
        private String name;
1939
        private DataType type;
1940
        private Map<String, String> sets;
1941
        private String sep;
1942

    
1943
        public PropertiesBuilder() {
1944
            this.sets = new LinkedHashMap<>();
1945
        }
1946

    
1947
        public void separator(String sep) {
1948
            this.sep = sep;
1949
        }
1950

    
1951
        public void name(String name) {
1952
            this.name = name;
1953
        }
1954

    
1955
        public void type(DataType type) {
1956
            this.type = type;
1957
        }
1958

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

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

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

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

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

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

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

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

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

    
2192
    public void setSRSForced(IProjection SRS) {
2193
        this.SRS = SRS;
2194
    }
2195

    
2196
    @Override
2197
    public JsonObject toJson() {
2198
        return this.toJsonBuilder().build();
2199
    }
2200

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

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

    
2228
        builder.add("geometryType", this.getGeomType());
2229
        builder.add("srs", this.getSRS());
2230

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

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

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

    
2275
        this.relationType = json.getInt("relationType");
2276
        this.displaySize = json.getInt("displaySize");
2277

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

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

    
2310
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2311

    
2312
        public TheJsonSerializer() {
2313
        }
2314

    
2315
        @Override
2316
        public Class getObjectClass() {
2317
            return DefaultFeatureAttributeDescriptor.class;
2318
        }
2319

    
2320
        @Override
2321
        public Object toObject(JsonObject json) {
2322
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2323
            o.fromJson(json);
2324
            return o;
2325
        }
2326

    
2327
        @Override
2328
        public JsonObjectBuilder toJsonBuilder(Object value) {
2329
            return ((SupportToJson) value).toJsonBuilder();
2330
        }
2331

    
2332
    }
2333

    
2334
    public static void selfRegister() {
2335
        Json.registerSerializer(new TheJsonSerializer());
2336
    }
2337

    
2338
    @Override
2339
    public String getDefaultFormat() {
2340
        return this.defaultFormat;
2341
    }
2342

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

    
2359
    
2360
}