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

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

    
103
@SuppressWarnings("UseSpecificCatch")
104
public class DefaultFeatureAttributeDescriptor implements
105
        FeatureAttributeDescriptor, Persistent, DynField_v2, DynField_LabelAttribute {
106

    
107
  protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureAttributeDescriptor.class);
108

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

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

    
159
  protected CoercionContext coerceContext = null; // not persistent
160
  protected MathContext mathContext = null; // not persistent
161

    
162
  private int relationType = RELATION_TYPE_NONE;
163
  protected Locale locale;
164
  protected int displaySize;
165

    
166
  public DefaultFeatureAttributeDescriptor() {
167
    // Usada en la persistencia
168
    this.precision = DataType.PRECISION_NONE;
169
    this.scale = DataType.SCALE_NONE;
170
    this.roundMode = BigDecimal.ROUND_HALF_UP;
171
  }
172

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

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

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

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

    
284
    // TODO: ? Habria que clonarlos ?
285
    this.availableValuesMethod = other.availableValuesMethod;
286
    this.calculateMethod = other.calculateMethod;
287
    this.relationType = other.relationType;
288
    this.locale = other.locale;
289
    this.displaySize = other.displaySize;
290
    this.avoidCachingAvailableValues = other.avoidCachingAvailableValues;
291
  }
292

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

    
303
  @Override
304
  public String getDataTypeName() {
305
    if (this.getDataType() == null) {
306
      return "(unknow)";
307
    }
308
    return this.getDataType().getName();
309
  }
310

    
311
  @Override
312
  public DefaultFeatureAttributeDescriptor getCopy() {
313
    return new DefaultFeatureAttributeDescriptor(this);
314
  }
315

    
316
  @Override
317
  public Object clone() throws CloneNotSupportedException {
318
    return new DefaultFeatureAttributeDescriptor(this);
319
  }
320

    
321
  @Override
322
  public boolean allowNull() {
323
    return allowNull;
324
  }
325

    
326
  @Override
327
  public Locale getLocale() {
328
    if( this.locale == null ) {
329
      if( this.dataType.isNumeric() ) {
330
        this.locale = Locale.ENGLISH;
331
      } else {
332
        this.locale = Locale.getDefault();
333
      }
334
    }
335
    return this.locale;
336
  }
337

    
338
  @Override
339
  public DataType getDataType() {
340
    if (featureAttributeGetter != null) {
341
      return featureAttributeGetter.getDataType();
342
    }
343
    return this.dataType;
344
  }
345

    
346
  public FeatureAttributeDescriptor setDataType(int type) {
347
    this.dataType = ToolsLocator.getDataTypesManager().get(type);
348
    return this;
349
  }
350

    
351
  @Override
352
  public DateFormat getDateFormat() {
353
    return this.dateFormat;
354
  }
355

    
356
  @Override
357
  public Object getDefaultValue() {
358
    return this.defaultValue;
359
  }
360

    
361
  @Override
362
  public Object getDefaultValueCoerced() {
363
    try {
364
      Object value = this.defaultValue;
365
      if (value == null) {
366
        return null;
367
      }
368
      if (ExpressionUtils.isDynamicText(value.toString())) {
369
        value = ExpressionUtils.evaluateDynamicText(value.toString());
370
      }
371
      return this.getDataType().coerce(value);
372
    } catch (CoercionException ex) {
373
      return null;
374
    }
375
  }
376
  
377
  @Override
378
  public Supplier getDefaultValueSupplier() {
379
      return (Supplier) this::getDefaultValueCoerced;
380
  }
381

    
382
    @Override
383
    public DynField setDefaultValueSupplier(Supplier supplier) {
384
        //Do nothing
385
        return this;
386
    }
387
  
388
  
389

    
390
  @Override
391
  public Evaluator getEvaluator() {
392
    return this.evaluator;
393
  }
394

    
395
  @Override
396
  public int getGeometryType() {
397
    if (this.dataType.getType() != DataTypes.GEOMETRY) {
398
      return Geometry.TYPES.UNKNOWN;
399
    }
400
    return this.geometryType;
401
  }
402

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

    
411
  @Override
412
  public GeometryType getGeomType() {
413
    if (this.dataType.getType() != DataTypes.GEOMETRY) {
414
      return null;
415
    }
416
    if (this.geomType == null) {
417
      try {
418
        this.geomType
419
                = GeometryLocator.getGeometryManager().getGeometryType(
420
                        this.geometryType, this.geometrySubType);
421
      } catch (GeometryException e) {
422
        throw new RuntimeException(
423
                "Error getting geometry type with type = "
424
                + this.geometryType + ", subtype = "
425
                + this.geometrySubType, e);
426
      }
427
    }
428
    return this.geomType;
429
  }
430

    
431
  @Override
432
  public int getIndex() {
433
    return this.index;
434
  }
435

    
436
  protected FeatureAttributeDescriptor setIndex(int index) {
437
    this.index = index;
438
    return this;
439
  }
440

    
441
  @Override
442
  public int getMaximumOccurrences() {
443
    return this.maximumOccurrences;
444
  }
445

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

    
451
  @Override
452
  public String getName() {
453
    return this.name;
454
  }
455

    
456
  public FeatureAttributeDescriptor setName(String name) {
457
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
458
    this.name = name;
459
    return this;
460
  }
461

    
462
  @Override
463
  public Class getObjectClass() {
464
    if (getDataType().getType() == DataTypes.OBJECT) {
465
      return objectClass;
466
    }
467
    return getDataType().getDefaultClass();
468
  }
469

    
470
  @Override
471
  public int getPrecision() {
472
    return this.precision;
473
  }
474

    
475
  @Override
476
  public int getScale() {
477
    return this.scale;
478
  }
479

    
480
  @Override
481
  public Coercion getCoercion() {
482
    return this.getDataType().getCoercion();
483
  }
484

    
485
  @Override
486
  public MathContext getMathContext() {
487
    if (this.mathContext == null) {
488
      if (this.getDataType().isNumeric()) {
489
        this.mathContext = new MathContext(
490
                this.getPrecision(),
491
                RoundingMode.valueOf(this.getRoundMode())
492
        );
493
      } else {
494
        this.mathContext = MathContext.UNLIMITED;
495
      }
496
    }
497
    return this.mathContext;
498
  }
499

    
500
  @Override
501
  public CoercionContext getCoercionContext() {
502
    if (this.coerceContext == null) {
503
      if (this.getDataType().isNumeric()) {
504
        this.coerceContext = DataTypeUtils.coerceContextDecimal(
505
                this.getLocale(),
506
                this.getPrecision(),
507
                this.getScale(),
508
                this.getRoundMode()
509
        );
510
      } else if( this.getType() == DataTypes.GEOMETRY ) {
511
          GeometryCoercionContext context = GeometryLocator.getGeometryManager().createGeometryCoercionContext();
512
          context.setGeometryType(this.getGeomType());
513
          context.setMode(GeometryCoercionContext.MODE_ONERROR_DONTCONVERT);
514
          this.coerceContext = context;
515
      } else {
516
        this.coerceContext = DataTypeUtils.coerceContextLocale(
517
                this.getLocale()
518
        );
519
      }
520
    }
521
    return this.coerceContext;
522
  }
523

    
524
  @Override
525
  public int getRoundMode() {
526
    return this.roundMode;
527
  }
528

    
529
  @Override
530
  public IProjection getSRS() {
531
    return this.SRS;
532
  }
533

    
534
  @Override
535
  public Interval getInterval() {
536
    return this.interval;
537
  }
538

    
539
  public IProjection getSRS(WeakReference storeRef) {
540
    if (this.SRS == null) {
541
      FeatureStore store = (FeatureStore) storeRef.get();
542
      this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
543
    }
544
    return this.SRS;
545
  }
546

    
547
  @Override
548
  public int getSize() {
549
    return this.size;
550
  }
551

    
552
  @Override
553
  public boolean isPrimaryKey() {
554
    return this.primaryKey;
555
  }
556

    
557
  @Override
558
  public boolean isReadOnly() {
559
    if (this.readOnly) {
560
      return true;
561
    }
562
    return this.isComputed();
563
  }
564

    
565
  @Override
566
  public String getAdditionalInfo(String infoName) {
567
    if (this.additionalInfo == null) {
568
      return null;
569
    }
570
    return this.additionalInfo.get(infoName);
571
  }
572

    
573
  @Override
574
  public boolean isAutomatic() {
575
    return this.isAutomatic;
576
  }
577

    
578
  @Override
579
  public boolean equals(Object obj) {
580
    if (this == obj) {
581
      return true;
582
    }
583
    if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
584
      return false;
585
    }
586
    DefaultFeatureAttributeDescriptor other
587
            = (DefaultFeatureAttributeDescriptor) obj;
588

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
645
    if (!Objects.equals(this.evaluator, other.evaluator)) {
646
      return false;
647
    }
648

    
649
    if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
650
      return false;
651
    }
652

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

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

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

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

    
669
    return true;
670
  }
671

    
672
  @Override
673
  public void loadFromState(PersistentState state)
674
          throws PersistenceException {
675
    allowNull = state.getBoolean("allowNull");
676
    dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
677
    dataProfile = state.getString("dataProfile");
678

    
679
//        FIXME: dateFormat;
680
    try {
681
      defaultValue = dataType.coerce(state.get("defaultValue"));
682
    } catch (CoercionException ex) {
683
    }
684

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

    
731
    Map<String, Object> values = state.getMap("availableValues");
732
    if (values == null || values.isEmpty()) {
733
      this.availableValues = null;
734
    } else {
735
      this.availableValues = new DynObjectValueItem[values.size()];
736
      int n = 0;
737
      for (Entry<String, Object> entry : values.entrySet()) {
738
        this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
739
      }
740
    }
741

    
742
    description = state.getString("description");
743
    minValue = state.get("minValue");
744
    maxValue = state.get("maxValue");
745
    label = state.getString("label");
746
    order = state.getInt("order");
747
    hidden = state.getBoolean("hidden");
748
    groupName = state.getString("groupName");
749
    relationType = state.getInt("relationType", RELATION_TYPE_NONE);
750

    
751
    foreingKey = (DefaultForeingKey) state.get("foreingKey");
752
    if (foreingKey != null) {
753
      this.foreingKey.setDescriptor(this);
754
    }
755
    tags = (Tags) state.get("tags");
756
    if (tags == null) {
757
      this.tags = new DefaultTags();
758
    }
759
    displaySize = state.getInt("displaySize",0);
760
    availableValuesExpression = (Expression) state.get("availableValuesExpression");
761
    avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues",false);
762
    availableValuesCache = null;
763
    
764
  }
765

    
766
  @Override
767
  public void saveToState(PersistentState state) throws PersistenceException {
768
    Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
769
    
770
    state.set("allowNull", allowNull);
771
    state.set("dataType", dataType.getType());
772
    state.set("dataProfile", dataProfile);
773

    
774
//        FIXME: dateFormat;
775
    state.set("defaultValue", Objects.toString(defaultValue, null));
776

    
777
    state.set("index", index);
778
    state.set("maximumOccurrences", maximumOccurrences);
779
    state.set("minimumOccurrences", minimumOccurrences);
780
    state.set("size", size);
781
    state.set("name", name);
782
    state.set("objectClass", objectClass == null ? null : objectClass.getName());
783
    state.set("precision", precision);
784
    state.set("scale", scale);
785
    state.set("roundMode", roundMode);    
786
    if( this.locale == null ) {
787
      state.setNull("locale");
788
    } else {
789
      state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
790
    }
791
    state.set("evaluator", evaluator);
792

    
793
    state.set("primaryKey", primaryKey);
794
    state.set("readOnly", readOnly);
795
    state.set("SRS", SRS);
796
    GeometryType theGeomType = this.getGeomType();
797
    if (theGeomType == null) {
798
      state.set("geometryType", Geometry.TYPES.UNKNOWN);
799
      state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
800
    } else {
801
      state.set("geometryType", theGeomType.getType());
802
      state.set("geometrySubType", theGeomType.getSubType());
803
    }
804

    
805
//      FIXME: additionalInfo
806
    state.set("isAutomatic", isAutomatic);
807
    state.set("isTime", isTime);
808
    if (this.interval == null) {
809
      state.setNull("interval_start");
810
      state.setNull("interval_end");
811
    } else {
812
      state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
813
      state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
814
    }
815
    state.set("SRS", SRS);
816

    
817
//      FIXME: featureAttributeGetter
818
    if (featureAttributeEmulator instanceof Persistent) {
819
      state.set("featureAttributeEmulator", featureAttributeEmulator);
820
    } else {
821
      state.setNull("featureAttributeEmulator");
822
    }
823

    
824
    state.set("indexed", indexed);
825
    state.set("isIndexAscending", isIndexAscending);
826
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
827

    
828
    if (this.availableValues == null) {
829
      state.setNull("availableValues");
830
    } else {
831
      Map<String, Object> values = new LinkedHashMap<>();
832
      for (DynObjectValueItem value : availableValues) {
833
        values.put(value.getLabel(), value.getValue());
834
      }
835
      state.set("availableValues", values);
836
    }
837
    state.set("description", description);
838
    state.set("minValue", minValue);
839
    state.set("maxValue", maxValue);
840
    state.set("label", label);
841
    state.set("order", order);
842
    state.set("hidden", hidden);
843
    state.set("groupName", groupName);
844
    state.set("relationType", relationType);
845

    
846
    state.set("foreingKey", this.foreingKey);
847
    state.set("tags", this.tags);
848

    
849
    state.set("displaySize", displaySize);
850
    state.set("availableValuesExpression", availableValuesExpression);
851
    state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);    
852
  }
853

    
854
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
855

    
856
  public static void registerPersistenceDefinition() {
857
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
858

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

    
912
      definition.addDynFieldObject("foreingKey")
913
              .setClassOfValue(DefaultForeingKey.class);
914

    
915
      definition.addDynFieldObject("tags")
916
              .setClassOfValue(Tags.class);
917

    
918
      definition.addDynFieldInt("displaySize").setMandatory(false);
919
      definition.addDynFieldObject("availableValuesExpression")
920
              .setClassOfValue(Expression.class)
921
              .setMandatory(false);
922
    }
923
  }
924

    
925
  /*
926
     * Start of DynField interface Implementation
927
     *
928
   */
929
  @Override
930
  public Tags getTags() {
931
    return tags;
932
  }
933

    
934
  @Override
935
  public boolean hasConstantAvailableValues() {
936
    return this.availableValues != null;
937
  }
938

    
939
  @Override
940
  public boolean isAvoidCachingAvailableValues() {
941
    return this.avoidCachingAvailableValues;
942
  }
943
  
944
  public boolean hasAvailableValues() {
945
      return getAvailableValues()!=null;
946
  }
947
  
948
  @Override
949
  public DynObjectValueItem[] getAvailableValues() {
950
    DynObjectValueItem[] values = this.availableValues;
951
    
952
    if (values != null) {
953
        return values;
954
    }
955
    values = this.availableValuesCache;
956
    if (values != null) {
957
        return values;
958
    }
959
    if (this.isForeingKey() && this.foreingKey.isClosedList()) {
960
      values = this.foreingKey.getAvailableValues(null);
961

    
962
    } else if( this.availableValuesExpression!=null ) {
963
      values = this.getAvailableValuesFromExpression();
964
    }
965
    if( !this.avoidCachingAvailableValues ) {
966
        this.availableValuesCache = values;
967
    }
968
    return values;
969
  }
970
  
971
    private DynObjectValueItem[] getAvailableValuesFrom(GetItemWithSize values) {
972
        if (values.size() == 0) {
973
            return null;
974
        }
975
        DynObjectValueItem[] r = null;
976
        Object firstelement = values.get(0);
977
        if (firstelement instanceof LabeledValue) {
978
            r = new DynObjectValueItem[values.size()];
979
            for (int i = 0; i < values.size(); i++) {
980
                LabeledValue v = (LabeledValue) values.get(i);
981
                r[i] = new DynObjectValueItem(
982
                        v.getValue(),
983
                        Objects.toString(v.getLabel(), Objects.toString(v.getValue(), String.valueOf(i)))
984
                );
985
            }
986
        } else if (firstelement instanceof Pair) {
987
            r = new DynObjectValueItem[values.size()];
988
            for (int i = 0; i < values.size(); i++) {
989
                Pair v = (Pair) values.get(i);
990
                r[i] = new DynObjectValueItem(
991
                        v.getValue(),
992
                        Objects.toString(v.getKey(), Objects.toString(v.getValue(), String.valueOf(i)))
993
                );
994
            }
995
        } else if (firstelement instanceof JsonObject) {
996
            JsonObject v = (JsonObject) firstelement;
997
            String labelname = null;
998
            for (String theName : new String[]{
999
                "name", "label", "key", "description"
1000
            }) {
1001
                if (v.containsKey(theName)) {
1002
                    labelname = theName;
1003
                    break;
1004
                }
1005
                if (v.containsKey(theName.toUpperCase())) {
1006
                    labelname = theName.toLowerCase();
1007
                    break;
1008
                }
1009
            }
1010
            String valuename = null;
1011
            if (v.containsKey("value")) {
1012
                valuename = "value";
1013
            }
1014
            r = new DynObjectValueItem[values.size()];
1015
            for (int i = 0; i < values.size(); i++) {
1016
                v = (JsonObject) values.get(i);
1017
                String theLabel;
1018
                Object theValue;
1019
                if (labelname == null) {
1020
                    theLabel = v.toString();
1021
                } else {
1022
                    theLabel = v.getString(labelname);
1023
                }
1024
                if (valuename == null) {
1025
                    theValue = v.getString(valuename);
1026
                } else {
1027
                    theValue = v;
1028
                }
1029
                r[i] = new DynObjectValueItem(theValue, theLabel);
1030
            }
1031
        } else if (firstelement instanceof Map) {
1032
            Map<String,Object> v = (Map<String,Object>) firstelement;
1033
            String labelname = null;
1034
            for (String theName : new String[]{
1035
                "name", "label", "key", "description"
1036
            }) {
1037
                if (v.containsKey(theName)) {
1038
                    labelname = theName;
1039
                    break;
1040
                }
1041
                if (v.containsKey(theName.toUpperCase())) {
1042
                    labelname = theName.toLowerCase();
1043
                    break;
1044
                }
1045
            }
1046
            String valuename = null;
1047
            if (v.containsKey("value")) {
1048
                valuename = "value";
1049
            }
1050
            r = new DynObjectValueItem[values.size()];
1051
            for (int i = 0; i < values.size(); i++) {
1052
                v = (Map<String,Object>) values.get(i);
1053
                String theLabel;
1054
                Object theValue;
1055
                if (labelname == null) {
1056
                    theLabel = v.toString();
1057
                } else {
1058
                    theLabel = (String) v.get(labelname);
1059
                }
1060
                if (valuename == null) {
1061
                    theValue = v;
1062
                } else {
1063
                    theValue = v.get(valuename);
1064
                }
1065
                r[i] = new DynObjectValueItem(theValue, theLabel);
1066
            }
1067
        } else if (firstelement instanceof Feature) {
1068
            Feature v = (Feature) firstelement;
1069
            FeatureType featureType = v.getType();
1070
            String valuename = null;
1071
            FeatureAttributeDescriptor[] pks = featureType.getPrimaryKey();
1072
            if( pks!=null && pks.length == 1) {
1073
                valuename = pks[0].getName();
1074
            }
1075
            String labelname = null;
1076
            for (String theName : new String[]{
1077
                "name", "label", "key", "description"
1078
            }) {
1079
                if (featureType.get(theName)!=null ) {
1080
                    labelname = theName;
1081
                    break;
1082
                }
1083
            }
1084
            r = new DynObjectValueItem[values.size()];
1085
            for (int i = 0; i < values.size(); i++) {
1086
                v = (Feature) values.get(i);
1087
                String theLabel;
1088
                Object theValue;
1089
                if (labelname == null) {
1090
                    theLabel = v.toString();
1091
                } else {
1092
                    theLabel = v.getString(labelname);
1093
                }
1094
                if( valuename == null ) {
1095
                    theValue = v.getReference().getCode();
1096
                } else {
1097
                    theValue = v.get(valuename);
1098
                }
1099
                r[i] = new DynObjectValueItem(theValue, theLabel);
1100
            }
1101
        }
1102
        return r;
1103
    }
1104
  
1105

    
1106
  private DynObjectValueItem[] getAvailableValuesFromExpression() {
1107
      if( this.availableValuesExpression == null || this.availableValuesExpression.isEmpty() ) {
1108
          return null;
1109
      }
1110
      try {
1111
        Object value = this.availableValuesExpression.execute(null);
1112
        if( value instanceof DynObjectValueItem[] ) {
1113
            return (DynObjectValueItem[]) value;
1114
        }
1115
        if( value instanceof List ) {
1116
            return this.getAvailableValuesFrom(new GetItemWithSize() {
1117
                @Override
1118
                public Object get(int i) {
1119
                    return ((List)value).get(i);
1120
                }
1121

    
1122
                @Override
1123
                public int size() {
1124
                    return ((List)value).size();
1125
                }
1126
            });
1127
        }
1128
      } catch(Throwable th) {
1129
          LOGGER.warn("Can't get available values from expression", th);
1130
      }
1131
      return null;
1132
  }
1133

    
1134
  @Override
1135
  public Expression getAvailableValuesExpression() {
1136
      return this.availableValuesExpression;
1137
  }
1138
  
1139
  @Override
1140
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1141
        if (StringUtils.isBlank(expression)) {
1142
            this.availableValuesExpression = null;
1143
            return this;
1144
        }
1145
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1146
        return this;
1147
    }
1148

    
1149
  @Override
1150
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1151
        this.availableValuesExpression = expression;
1152
        return this;
1153
    }
1154
  
1155
  @Override
1156
  public String getLabelOfValue(Object value) {
1157
    if (this.labelOfValueMap != null) {
1158
      String theLabel = this.labelOfValueMap.get(value);
1159
      if (theLabel == null) {
1160
        theLabel = Objects.toString(value, "");
1161
      }
1162
      return theLabel;
1163
    }
1164
    DynObjectValueItem[] values = this.getAvailableValues();
1165
    if (values == null) {
1166
      return Objects.toString(value, "");
1167
    }
1168
    Map<Object, String> map = new LinkedHashMap<>();
1169
    for (DynObjectValueItem theValue : values) {
1170
      map.put(theValue.getValue(), theValue.getLabel());
1171
    }
1172
    this.labelOfValueMap = map;
1173
    String theLabel = this.labelOfValueMap.get(value);
1174
    if (theLabel == null) {
1175
      theLabel = Objects.toString(value, "");
1176
    }
1177
    return theLabel;
1178
  }
1179

    
1180
  @Override
1181
  public String getDescription() {
1182
    if (this.description == null) {
1183
      return getName();
1184
    }
1185
    return this.description;
1186
  }
1187

    
1188
  @Override
1189
  public Object getMaxValue() {
1190
    return this.maxValue;
1191
  }
1192

    
1193
  @Override
1194
  public Object getMinValue() {
1195
    return this.minValue;
1196
  }
1197

    
1198
  @Override
1199
  public int getTheTypeOfAvailableValues() {
1200
    return 1;
1201
  }
1202

    
1203
  @Override
1204
  public int getType() {
1205
    if (featureAttributeGetter != null) {
1206
      return featureAttributeGetter.getDataType().getType();
1207
    }
1208
    return getDataType().getType();
1209
  }
1210

    
1211
  @Override
1212
  public boolean isMandatory() {
1213
    return !allowNull() || isPrimaryKey();
1214
  }
1215

    
1216
  @Override
1217
  public boolean isPersistent() {
1218
    return false;
1219
  }
1220

    
1221
  @Override
1222
  public DynField setAvailableValues(DynObjectValueItem[] values) {
1223
    if (ArrayUtils.isEmpty(values)) {
1224
      this.availableValues = null;
1225
    } else {
1226
      this.availableValues = values;
1227
    }
1228
    return this;
1229
  }
1230

    
1231
  @Override
1232
  public DynField setDescription(String description) {
1233
    this.description = description;
1234
    return this;
1235
  }
1236

    
1237
  @Override
1238
  public DynField setMandatory(boolean mandatory) {
1239
    throw new UnsupportedOperationException();
1240
  }
1241

    
1242
  @Override
1243
  public DynField setMaxValue(Object maxValue) {
1244
    try {
1245
      this.maxValue = this.coerce(maxValue);
1246
    } catch (CoercionException e) {
1247
      throw new IllegalArgumentException(e);
1248
    }
1249
    return this;
1250
  }
1251

    
1252
  @Override
1253
  public DynField setMinValue(Object minValue) {
1254
    try {
1255
      this.maxValue = this.coerce(minValue);
1256
    } catch (CoercionException e) {
1257
      throw new IllegalArgumentException(e);
1258
    }
1259
    return this;
1260
  }
1261

    
1262
  @Override
1263
  public DynField setPersistent(boolean persistent) {
1264
    throw new UnsupportedOperationException();
1265
  }
1266

    
1267
  @Override
1268
  public DynField setTheTypeOfAvailableValues(int type) {
1269
    throw new UnsupportedOperationException();
1270
  }
1271

    
1272
  @Override
1273
  public DynField setType(int type) {
1274
    throw new UnsupportedOperationException();
1275
  }
1276

    
1277
  @Override
1278
  @Deprecated
1279
  public DynField setDefaultDynValue(Object defaultValue) {
1280
    return this.setDefaultFieldValue(defaultValue);
1281
  }
1282

    
1283
  @Override
1284
  public DynField setDefaultFieldValue(Object defaultValue) {
1285
    this.defaultValue = defaultValue;
1286
    return this;
1287
  }
1288

    
1289
  @Override
1290
  public Class getClassOfValue() {
1291
    return null;
1292
  }
1293

    
1294
  @Override
1295
  public DynField getElementsType() {
1296
    return null;
1297
  }
1298

    
1299
  @Override
1300
  public DynField setClassOfValue(Class theClass)
1301
          throws DynFieldIsNotAContainerException {
1302
    throw new UnsupportedOperationException();
1303
  }
1304

    
1305
  @Override
1306
  public DynField setElementsType(DynStruct type)
1307
          throws DynFieldIsNotAContainerException {
1308
    throw new UnsupportedOperationException();
1309
  }
1310

    
1311
  @Override
1312
  public DynField setElementsType(int type)
1313
          throws DynFieldIsNotAContainerException {
1314
    throw new UnsupportedOperationException();
1315
  }
1316

    
1317
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1318
    this.dataProfile = dataProfile;
1319
    return this;
1320
  }
1321

    
1322
  @Override
1323
  public String getDataProfileName() {
1324
    return dataProfile;
1325
  }
1326

    
1327
  @Override
1328
  public DataProfile getDataProfile() {
1329
    if (StringUtils.isBlank(dataProfile)) {
1330
      return null;
1331
    }
1332
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1333
    return profile;
1334
  }
1335

    
1336
  @Override
1337
  public void validate(Object value) throws DynFieldValidateException {
1338

    
1339
    if (value == null && !this.allowNull()) {
1340
      throw new DynFieldValidateException(value, this, null);
1341
    }
1342

    
1343
    try {
1344
      this.dataType.coerce(value);
1345
    } catch (CoercionException e) {
1346
      throw new DynFieldValidateException(value, this, e);
1347
    }
1348

    
1349
    /*
1350
         * Other checks will be needed
1351
     */
1352
  }
1353

    
1354
  @Override
1355
  public String getSubtype() {
1356
    if (featureAttributeGetter != null) {
1357
      return featureAttributeGetter.getDataType().getSubtype();
1358
    }
1359
    return this.dataType.getSubtype();
1360
  }
1361

    
1362
  @Override
1363
  public Object coerce(Object value) throws CoercionException {
1364
    if (value == null) {
1365
      return value; // O debe devolver this.defaultValue
1366
    }
1367
    try {
1368
      return this.getDataType().coerce(value, this.getCoercionContext());
1369
    } catch (Exception ex) {
1370
      throw new RuntimeException(ex);
1371
    }
1372
  }
1373

    
1374
  @Override
1375
  public DynField setAvailableValues(List values) {
1376
    if (values == null || values.isEmpty()) {
1377
      this.availableValues = null;
1378
    } else {
1379
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1380
              new DynObjectValueItem[values.size()]
1381
      );
1382
    }
1383
    return this;
1384
  }
1385

    
1386
  @Override
1387
  public String getGroup() {
1388
    return this.groupName;
1389
  }
1390

    
1391
  @Override
1392
  public int getOder() {
1393
    return this.order;
1394
  }
1395

    
1396
  @Override
1397
  public String getLabel() {
1398
    if (this.label == null) {
1399
      return this.getName();
1400
    }
1401
    return this.label;
1402
  }
1403

    
1404
  @Override
1405
  public String getLocalizedLabel() {
1406
    if (StringUtils.isBlank(this.label)) {
1407
      return this.getName();
1408
    }
1409
    I18nManager i18n = ToolsLocator.getI18nManager();
1410
    return i18n.getTranslation(this.label);
1411
  }
1412

    
1413
  @Override
1414
  public DynField setLabel(String label) {
1415
    this.label = label;
1416
    return this;
1417
  }
1418

    
1419
  @Override
1420
  public DynField setShortLabel(String shortLabel) {
1421
    this.shortLabel = shortLabel;
1422
    return this;
1423
  }
1424

    
1425
  @Override
1426
  public String getShortLabel() {
1427
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1428
  }
1429

    
1430
  @Override
1431
  public String getLocalizedShortLabel() {
1432
    if (StringUtils.isBlank(shortLabel)) {
1433
      return this.getLocalizedLabel();
1434
    }
1435
    I18nManager i18n = ToolsLocator.getI18nManager();
1436
    return i18n.getTranslation(shortLabel);
1437
  }
1438

    
1439
  @Override
1440
  public DynField setGroup(String groupName) {
1441
    this.groupName = groupName;
1442
    return this;
1443
  }
1444

    
1445
  @Override
1446
  public DynField setOrder(int order) {
1447
    this.order = order;
1448
    return this;
1449
  }
1450

    
1451
  @Override
1452
  public DynField setHidden(boolean hidden) {
1453
    this.hidden = hidden;
1454
    return this;
1455
  }
1456

    
1457
  @Override
1458
  public boolean isHidden() {
1459
    return this.hidden;
1460
  }
1461

    
1462
  @Override
1463
  public DynField setReadOnly(boolean readOnly) {
1464
    this.readOnly = readOnly;
1465
    return this;
1466
  }
1467

    
1468
  @Override
1469
  public boolean isContainer() {
1470
    return false;
1471
  }
1472

    
1473
  @Override
1474
  public Class getClassOfItems() {
1475
    return null;
1476
  }
1477

    
1478
  @Override
1479
  public DynField setClassOfItems(Class theClass) {
1480
    throw new UnsupportedOperationException();
1481
  }
1482

    
1483
  @Override
1484
  public DynField setType(DataType type) {
1485
    throw new UnsupportedOperationException();
1486
  }
1487

    
1488
  @Override
1489
  public DynField setSubtype(String subtype) {
1490
    throw new UnsupportedOperationException();
1491
  }
1492

    
1493
  @Override
1494
  public boolean isTime() {
1495
    return isTime;
1496
  }
1497

    
1498
  @Override
1499
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1500
    return featureAttributeGetter;
1501
  }
1502

    
1503
  @Override
1504
  public void setFeatureAttributeGetter(
1505
          FeatureAttributeGetter featureAttributeTransform) {
1506
    this.featureAttributeGetter = featureAttributeTransform;
1507
  }
1508

    
1509
  @Override
1510
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1511
    return this.featureAttributeEmulator;
1512
  }
1513

    
1514
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1515
    this.featureAttributeEmulator = featureAttributeEmulator;
1516
    return this;
1517
  }
1518

    
1519
  @Override
1520
  public boolean isIndexed() {
1521
    return this.indexed;
1522
  }
1523

    
1524
  @Override
1525
  public boolean isForeingKey() {
1526
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1527
  }
1528

    
1529
  @Override
1530
  public ForeingKey getForeingKey() {
1531
    return this.foreingKey;
1532
  }
1533

    
1534
  @Override
1535
  public boolean allowIndexDuplicateds() {
1536
    return this.allowIndexDuplicateds;
1537
  }
1538

    
1539
  @Override
1540
  public boolean isIndexAscending() {
1541
    return this.isIndexAscending;
1542
  }
1543

    
1544
  @Override
1545
  public DynField setClassOfValue(DynStruct dynStrct) {
1546
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1547
  }
1548

    
1549
  @Override
1550
  public DynField setClassOfValue(String theClassNameOfValue) {
1551
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1552
  }
1553

    
1554
  @Override
1555
  public String getClassNameOfValue() {
1556
    return null;
1557
  }
1558

    
1559
  @Override
1560
  public DynStruct getDynClassOfValue() {
1561
    return null;
1562
  }
1563

    
1564
  @Override
1565
  public DynField setTypeOfItems(int type) {
1566
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1567
  }
1568

    
1569
  @Override
1570
  public int getTypeOfItems() {
1571
    return DataTypes.INVALID;
1572
  }
1573

    
1574
  @Override
1575
  public DynField setClassOfItems(DynStruct dynStrct) {
1576
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1577
  }
1578

    
1579
  @Override
1580
  public DynField setClassOfItems(String theClassNameOfValue) {
1581
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1582
  }
1583

    
1584
  @Override
1585
  public String getClassNameOfItems() {
1586
    return null;
1587
  }
1588

    
1589
  @Override
1590
  public DynStruct getDynClassOfItems() {
1591
    return null;
1592
  }
1593

    
1594
  @Override
1595
  public DynField setRelationType(int relationType) {
1596
    this.relationType = relationType;
1597
    return this;
1598
  }
1599

    
1600
  @Override
1601
  public int getRelationType() {
1602
    return this.relationType;
1603
  }
1604

    
1605
  @Override
1606
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1607
    this.availableValuesMethod = availableValuesMethod;
1608
    return this;
1609
  }
1610

    
1611
  @Override
1612
  public DynObjectValueItem[] getAvailableValues(DynObject self) {
1613
    if (this.availableValuesMethod != null) {
1614
      DynObjectValueItem[] values;
1615
      try {
1616
        values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self, new Object[]{this});
1617
      } catch (DynMethodException ex) {
1618
        return this.availableValues;
1619
      }
1620
      if (values != null) {
1621
        return values;
1622
      }
1623
    }
1624
    return this.availableValues;
1625
  }
1626

    
1627
  @Override
1628
  public DynMethod getAvailableValuesMethod() {
1629
    return this.availableValuesMethod;
1630
  }
1631

    
1632
  @Override
1633
  public boolean isAvailableValuesCalculated() {
1634
    return this.availableValuesMethod != null;
1635
  }
1636

    
1637
  @Override
1638
  public DynMethod getCalculateMethod() {
1639
    return this.calculateMethod;
1640
  }
1641

    
1642
  @Override
1643
  public DynField setCalculateMethod(DynMethod method) {
1644
    this.calculateMethod = method;
1645
    return this;
1646
  }
1647

    
1648
  @Override
1649
  public boolean isCalculated() {
1650
    return this.calculateMethod != null;
1651
  }
1652

    
1653
  @Override
1654
  public Object getCalculatedValue(DynObject self) {
1655
    try {
1656
      return this.calculateMethod.invoke(self, new Object[]{this});
1657
    } catch (DynMethodException ex) {
1658
      throw new RuntimeException(ex);
1659
    }
1660
  }
1661

    
1662
  @Override
1663
  public DynField setValidateElements(boolean validate) {
1664
    return this;
1665
  }
1666

    
1667
  @Override
1668
  public boolean getValidateElements() {
1669
    return false;
1670
  }
1671

    
1672
  @Override
1673
  public boolean hasLabel() {
1674
    return StringUtils.isNotBlank(this.label);
1675
  }
1676

    
1677
  @Override
1678
  public boolean hasShortLabel() {
1679
    return StringUtils.isNotBlank(this.shortLabel);
1680
  }
1681

    
1682
  @Override
1683
  public boolean hasDescription() {
1684
    return StringUtils.isNotBlank(this.description);
1685
  }
1686

    
1687
  @Override
1688
  public FeatureAttributeDescriptor getValue() {
1689
    return this;
1690
  }
1691

    
1692
  @Override
1693
  public int getDisplaySize() {
1694
    return this.displaySize;
1695
  }
1696

    
1697
    @Override
1698
    public boolean isInAvailableValues(Object valueToCheck) {
1699
        if (this.getAvailableValues()!=null) {
1700
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1701
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1702
                    return true;
1703
                }
1704
            }
1705
        }
1706
        return false;
1707
    }
1708

    
1709
  private class ConstantValueEvaluator extends AbstractEvaluator {
1710

    
1711
    @Override
1712
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1713
      return defaultValue;
1714
    }
1715

    
1716
    @Override
1717
    public String getName() {
1718
      return "Constant attribute " + name;
1719
    }
1720
  }
1721

    
1722
  public void setConstantValue(boolean isConstantValue) {
1723
    if (isConstantValue) {
1724
      /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1725
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1726
             * el evaluador el que se encarga de proporcionar su valor.
1727
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1728
             * por defecto para ese attributo.
1729
       */
1730
      this.evaluator = new ConstantValueEvaluator();
1731
    } else {
1732
      this.evaluator = null;
1733
    }
1734
  }
1735

    
1736
  @Override
1737
  public boolean isComputed() {
1738
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1739
  }
1740

    
1741
  @Override
1742
  public FeatureStore getStore() {
1743
    FeatureType ftype = this.getFeatureType();
1744
    if (ftype == null) {
1745
      return null;
1746
    }
1747
    return ftype.getStore();
1748
  }
1749

    
1750
  @Override
1751
  public FeatureType getFeatureType() {
1752
    if (this.typeRef == null) {
1753
      return null;
1754
    }
1755
    FeatureType ftype = (FeatureType) this.typeRef.get();
1756
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1757
    return ftype;
1758
  }
1759

    
1760
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1761
    this.interval = interval;
1762
    return this;
1763
  }
1764

    
1765
  public void fixAll() {
1766
    if (!this.getDataType().supportSize()) {
1767
      this.size = 0;
1768
    }
1769
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1770
    this.precision = ps.getPrecision();
1771
    this.scale = ps.getScale();
1772

    
1773
    switch (this.getType()) {
1774
      case DataTypes.INSTANT:
1775
      case DataTypes.INTERVAL:
1776
      case DataTypes.DATE:
1777
      case DataTypes.TIME:
1778
      case DataTypes.TIMESTAMP:
1779
        if (this.getInterval() != null) {
1780
          this.isTime = true;
1781
        }
1782
        break;
1783
    }
1784
  }
1785

    
1786
  @Override
1787
  public String[] getRequiredFieldNames() {
1788
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1789
    if (emulator == null) {
1790
      return null;
1791
    }
1792
    return emulator.getRequiredFieldNames();
1793
  }
1794

    
1795
  @Override
1796
  public void recentUsed() {
1797
    DefaultFeatureType.RECENTS_USEDS.add(this);
1798
  }
1799

    
1800
  @Override
1801
  public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1802
    if (other == null) {
1803
      throw new NullPointerException();
1804
    }
1805
    DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1806
    if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1807
      return false;
1808
    }
1809
    if (old.isComputed() && old.isComputed() == this.isComputed()) {
1810
      return true;
1811
    }
1812
    if (this.dataType != old.dataType) {
1813
      return false;
1814
    }
1815
    if (this.size != old.size) {
1816
      return false;
1817
    }
1818
    if (this.precision != old.precision) {
1819
      return false;
1820
    }
1821
//        if( this.primaryKey != old.primaryKey ) {
1822
//            return false;
1823
//        }
1824
    if (this.geomType != old.geomType) {
1825
      return false;
1826
    }
1827
    if (this.SRS != old.SRS) {
1828
      return false;
1829
    }
1830
    if (this.isAutomatic != old.isAutomatic) {
1831
      return false;
1832
    }
1833
    return true;
1834
  }
1835
  
1836
  private class PropertiesBuilder {
1837

    
1838
        private String name;
1839
        private DataType type;
1840
        private Map<String,String> sets;
1841
        private String sep;
1842
      
1843
      public PropertiesBuilder() {
1844
          this.sets = new LinkedHashMap<>();
1845
      }
1846
      
1847
      public void separator(String sep) {
1848
          this.sep = sep;
1849
      }
1850
      
1851
      public void name(String name) {
1852
        this.name = name;
1853
      }
1854
      
1855
      public void type(DataType type) {
1856
          this.type = type;
1857
      }
1858
      
1859
      public void set(String name, ForeingKey fk) {
1860
          if( fk == null ) {
1861
              return;
1862
          }
1863
          if( !fk.isForeingKey() ) {
1864
              return;
1865
          }
1866
          this.set(name, fk.isForeingKey());
1867
          this.set(name+"_code", fk.getCodeName());
1868
          this.set(name+"_label", fk.getLabelFormula());
1869
          this.set(name+"_closedlist", fk.isClosedList());
1870
          this.set(name+"_table", fk.getTableName());
1871
      }
1872

    
1873
      public void set(String name, FeatureAttributeEmulator value) {
1874
          if( value == null ) {
1875
              return;
1876
          }
1877
          if( value instanceof FeatureAttributeEmulatorExpression ) {
1878
            this.set(name, ((FeatureAttributeEmulatorExpression)value).getExpression().getPhrase());
1879
          }
1880
      }
1881
      
1882
      public void set(String name, IProjection value) {
1883
          if( value == null ) {
1884
              return;
1885
          }
1886
          this.set(name, value.getAbrev());
1887
      }
1888
      
1889
      public void set(String name, GeometryType value) {
1890
          if( value == null ) {
1891
              return;
1892
          }
1893
          this.set(name, value.getFullName().replace(":", "@"));
1894
      }
1895
      
1896
      public void set(String name, Object value) {
1897
          if( value == null ) {
1898
              return;
1899
          }
1900
          String s = Objects.toString(value, "");
1901
          if( StringUtils.isBlank(s) ) {
1902
              return;
1903
          }
1904
          this.sets.put(name, s);
1905
      }
1906
      
1907
      public void set(String name, Object value, Object skipValue) {
1908
          if( value == null || value == skipValue) {
1909
              return;
1910
          }
1911
          String s = Objects.toString(value, "");
1912
          if( StringUtils.isBlank(s) ) {
1913
              return;
1914
          }
1915
          this.sets.put(name, s);
1916
      }
1917
      
1918
      @Override
1919
      public String toString() {        
1920
        StringBuilder builder = new StringBuilder();
1921
        builder.append(this.name);
1922
        builder.append(sep);        
1923
        builder.append(this.type.getName());
1924
        for (String key : this.sets.keySet()) {
1925
            builder.append(sep);        
1926
            builder.append("set");
1927
            builder.append(sep);        
1928
            builder.append(key);        
1929
            builder.append("=");        
1930
            builder.append(this.sets.get(key));                    
1931
        }
1932
        return builder.toString();
1933
      }
1934
  }
1935

    
1936
  private String getAll() {
1937
    PropertiesBuilder builder = new PropertiesBuilder();
1938
    builder.separator("/");
1939
    builder.name(this.name);
1940
    builder.type(this.dataType);
1941
    builder.set("size", this.size, 0);
1942
    switch(this.getType()) {
1943
        case DataTypes.BYTE:
1944
        case DataTypes.INTEGER:
1945
        case DataTypes.LONG:
1946
            break;
1947
        case DataTypes.FLOAT:
1948
        case DataTypes.DOUBLE:
1949
            builder.set("locale", this.getLocale());
1950
            break;
1951
        case DataTypes.DECIMAL:
1952
            builder.set("precision", this.precision);
1953
            builder.set("scale", this.scale);
1954
            builder.set("roundMode", this.getRoundMode());
1955
            builder.set("locale", this.getLocale());
1956
            break;
1957
        case DataTypes.DATE:
1958
        case DataTypes.TIME:
1959
        case DataTypes.TIMESTAMP:
1960
            builder.set("locale", this.getLocale());
1961
            break;
1962
        case DataTypes.GEOMETRY:
1963
            IProjection proj = this.getSRS();
1964
            if( proj!=null ) {
1965
                builder.set("srs", proj.getAbrev().replace(":", "@"));
1966
            }
1967
            GeometryType theGeomType = this.getGeomType();
1968
            if( theGeomType!=null ) {
1969
                String geomTypeName = GeometryUtils.getGeometryTypeName(this.getGeomType().getType());
1970
                String geomSubtypeName = GeometryUtils.getGeometrySubtypeName(this.getGeomType().getSubType());
1971
                builder.set("geomtype", geomTypeName+"@"+geomSubtypeName);
1972
            }
1973
            break;
1974
    }
1975
    builder.set("hidden", this.isHidden(), false);
1976
    builder.set("readOnly", this.isReadOnly(), false);
1977
    builder.set("allowNull", this.allowNull(), true);
1978
    builder.set("pk", this.isPrimaryKey(), false);
1979
    builder.set("automatic", this.isAutomatic(), false);
1980
    builder.set("isTime", this.isTime(), false);
1981
    builder.set("profile", this.getDataProfileName());
1982
    builder.set("group", this.getGroup());
1983
    builder.set("description", this.description);
1984
    builder.set("label", this.label);
1985
    builder.set("shortLabel", this.shortLabel);
1986
    builder.set("order", this.getOder());
1987
    if( this.getFeatureAttributeEmulator() instanceof FeatureAttributeEmulatorExpression ) {
1988
        Expression exp = ((FeatureAttributeEmulatorExpression)this.getFeatureAttributeEmulator()).getExpression();
1989
        if( exp!=null ) {
1990
            builder.set("expression", exp.getPhrase());
1991
        }
1992
    }
1993
    builder.set("isAvoidCachingAvailableValues", this.isAvoidCachingAvailableValues(), false);
1994
    if( this.isForeingKey() ) {
1995
        builder.set("fk", this.isForeingKey());
1996
        builder.set("fk_table", this.getForeingKey().getTableName());
1997
        builder.set("fk_code", this.getForeingKey().getCodeName());
1998
        builder.set("fk_label", this.getForeingKey().getLabelFormula());
1999
        builder.set("fk.closedlist", this.getForeingKey().isClosedList());
2000
    }
2001
    return builder.toString();
2002
  }
2003
  
2004
  @Override
2005
  public Object get(String name) {
2006
      if (StringUtils.isBlank(name)) {
2007
          throw new IllegalArgumentException("Name can't be empty");
2008
      }
2009
      switch (name.trim().toLowerCase()) {
2010
          case "all":
2011
              return this.getAll();
2012
          case "isreadonly":
2013
          case "readonly":
2014
              return this.isReadOnly();
2015
          case "hidden":
2016
              return this.isHidden();
2017
          case "allownull":
2018
              return this.allowNull();
2019
          case "pk":
2020
          case "ispk":
2021
          case "primarykey":
2022
          case "isprimarykey":
2023
              return this.isPrimaryKey();
2024
          case "isautomatic":
2025
          case "automatic":
2026
              return this.isAutomatic();
2027
          case "time":
2028
          case "istime":
2029
              return this.isTime();
2030
          case "profile":
2031
              return this.getDataProfile();
2032
          case "group":
2033
              return this.getGroup();
2034
          case "description":
2035
              return this.getDescription();
2036
          case "label":
2037
              return this.getLabel();
2038
          case "shortlabel":
2039
              return this.getShortLabel();
2040
          case "isavoidcachingavailablevalues":
2041
          case "avoidcachingavailablevalues":
2042
          case "nocachingavailablevalues":
2043
              return this.isAvoidCachingAvailableValues();
2044
          case "expression":
2045
              return this.getFeatureAttributeEmulator();
2046
          case "size":
2047
              return this.getSize();
2048
          case "precision":
2049
              return this.getPrecision();
2050
          case "scale":
2051
              return this.getScale();
2052
          case "roundmode":
2053
              return this.getRoundMode();
2054
          case "locale":
2055
              return this.getLocale();
2056
          case "order":
2057
              return this.getOder();
2058
          case "isfk":
2059
          case "isforeingkey":
2060
              return this.isForeingKey();
2061
          case "fk":
2062
          case "foreingkey":
2063
              return this.getForeingKey();
2064
          case "fk_code":
2065
          case "foreingkey_code":
2066
          case "foreingkey.code":
2067
              return this.getForeingKey().getCodeName();
2068
          case "fk_label":
2069
          case "foreingkey_label":
2070
          case "foreingkey.label":
2071
              return this.getForeingKey().getLabelFormula();
2072
          case "fk.closedlist":
2073
          case "foreingkey_closedlist":
2074
          case "foreingkey.closedlist":
2075
              return this.getForeingKey().isClosedList();
2076
          case "fk_table":
2077
          case "foreingkey_table":
2078
          case "foreingkey.table":
2079
              return this.getForeingKey().getTableName();
2080
          case "interval":
2081
              return this.getInterval();
2082
          case "geomtype":
2083
          case "geometrytype":
2084
              return this.getGeomType();
2085
          case "srs":
2086
              return this.getSRS();
2087
          default:
2088
              throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
2089
      }
2090
  }
2091
  
2092
    public void setSRSForced(IProjection SRS) {
2093
        this.SRS = SRS;
2094
    }
2095
    
2096
    @Override
2097
    public JsonObject toJson() {
2098
        return this.toJsonBuilder().build();
2099
    }
2100

    
2101
    @Override
2102
    public JsonObjectBuilder toJsonBuilder() {
2103
        JsonObjectBuilder builder = Json.createObjectBuilder();
2104
        builder.add_class(this);
2105
        builder.add("name", this.name);
2106
        builder.add("description", this.description);
2107
        builder.add("label", this.label);
2108
        builder.add("shortLabel", this.shortLabel);
2109
        builder.add("order", this.order);
2110
        builder.add("groupName", this.groupName);
2111
        builder.add("dataType", this.dataType);
2112
        builder.add("size", this.size);
2113
        builder.add("precision", this.precision);
2114
        builder.add("scale", this.scale);
2115
        builder.add("roundMode", this.roundMode);
2116

    
2117
        builder.add("allowNull", this.allowNull);
2118
        builder.add("primaryKey", this.primaryKey);
2119
        builder.add("readOnly", this.readOnly);
2120
        builder.add("isAutomatic", this.isAutomatic);
2121
        builder.add("isTime", this.isTime);
2122
        builder.add("indexed", this.indexed);
2123
        builder.add("isIndexAscending", this.isIndexAscending);
2124
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2125
        builder.add("hidden", this.hidden);
2126
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2127

    
2128
        builder.add("geometryType",this.getGeomType());
2129
        builder.add("srs", this.getSRS());
2130

    
2131
        builder.add("relationType", this.relationType);
2132
        builder.add("displaySize", this.displaySize);
2133
        builder.add("locale", this.getLocale());
2134
        builder.add("expression", this.getFeatureAttributeEmulator());
2135
        if( this.isForeingKey() ) {
2136
            builder.add("fk", this.isForeingKey());
2137
            builder.add("fk_table", this.getForeingKey().getTableName());
2138
            builder.add("fk_code", this.getForeingKey().getCodeName());
2139
            builder.add("fk_label", this.getForeingKey().getLabelFormula());
2140
            builder.add("fk_closedlist", this.getForeingKey().isClosedList());
2141
        }
2142
        builder.add("availableValuesExpression", this.availableValuesExpression);
2143
        builder.add("defaultValue", Objects.toString(this.defaultValue,""));
2144
        builder.add("dataProfile", this.getDataProfileName());
2145
        builder.add("tags", tags);
2146
        builder.add("availableValues", availableValues);
2147
        builder.add("additionalInfo", this.additionalInfo);
2148
        return builder;
2149
    }
2150
    
2151
    public void fromJson(JsonObject json) {
2152
        this.name = json.getString("name");
2153
        this.description = json.getString("description");
2154
        this.label = json.getString("label");
2155
        this.shortLabel = json.getString("shortLabel");
2156
        this.order = json.getInt("order");
2157
        this.groupName = json.getString("groupName");
2158
        this.precision = json.getInt("precision");
2159
        this.size = json.getInt("size");
2160
        this.scale = json.getInt("scale");
2161
        this.roundMode = json.getInt("roundMode");
2162
        
2163
        this.allowNull = json.getBoolean("allowNull");       
2164
        this.primaryKey = json.getBoolean("primaryKey");
2165
        this.readOnly = json.getBoolean("readOnly");
2166
        this.isAutomatic = json.getBoolean("isAutomatic");
2167
        this.isTime = json.getBoolean("isTime");
2168
        this.indexed = json.getBoolean("indexed");
2169
        this.isIndexAscending = json.getBoolean("isIndexAscending");
2170
        this.allowIndexDuplicateds = json.getBoolean("allowIndexDuplicateds");
2171
        this.hidden = json.getBoolean("hidden");
2172
        this.avoidCachingAvailableValues = json.getBoolean("avoidCachingAvailableValues");
2173

    
2174
        this.relationType = json.getInt("relationType");
2175
        this.displaySize = json.getInt("displaySize");
2176

    
2177
        this.dataType = (DataType) Json.toObject(json,"dataType");
2178
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2179
        this.SRS = (IProjection) Json.toObject(json, "srs");
2180
        this.locale = (Locale) Json.toObject(json, "locale");
2181
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json,"expression");
2182

    
2183
        this.tags = (Tags) Json.toObject(json, "tags");
2184
        this.additionalInfo = Json.toMap(json, "additionalInfo");
2185
        this.availableValues = (DynObjectValueItem[]) Json.toArray(json, "availableValues", new DynObjectValueItem[0]);
2186
        this.dataProfile = json.getString("dataProfile", null);
2187
        try {
2188
            this.defaultValue = this.coerce(json.getString("defaultValue", null));
2189
        } catch(Exception ex) {
2190
            LOGGER.warn("Can't retrive default value for attribute '"+this.name+"'.",ex);
2191
        }
2192
        this.availableValuesExpression = (Expression) Json.toObject(json,"availableValuesExpression");
2193
        if( json.getBoolean("fk", false) ) {
2194
            this.foreingKey = new DefaultForeingKey();
2195
            this.foreingKey.setTableName(json.getString("fk_table", null));
2196
            this.foreingKey.setCodeName(json.getString("fk_code", null));
2197
            this.foreingKey.setLabelFormula(json.getString("fk_label", null));
2198
            this.foreingKey.setClosedList(json.getBoolean("fk_closedlist", false));
2199
        }
2200
    }
2201
    
2202
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2203
        
2204
        public TheJsonSerializer() {            
2205
        }
2206

    
2207
        @Override
2208
        public Class getObjectClass() {
2209
            return DefaultFeatureAttributeDescriptor.class;
2210
        }
2211

    
2212
        @Override
2213
        public Object toObject(JsonObject json) {
2214
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2215
            o.fromJson(json);
2216
            return o;
2217
        }
2218

    
2219
        @Override
2220
        public JsonObjectBuilder toJsonBuilder(Object value) {
2221
            return ((SupportToJson)value).toJsonBuilder();
2222
        }
2223
        
2224
    }
2225

    
2226
    public static void selfRegister() {
2227
        Json.registerSerializer(new TheJsonSerializer());
2228
    }
2229

    
2230
}