Statistics
| Revision:

svn-gvsig-desktop / branches / org.gvsig.desktop-cvsgis1 / 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 @ 45267

History | View | Annotate | Download (66.8 KB)

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

    
25
import java.lang.ref.WeakReference;
26
import java.math.BigDecimal;
27
import java.math.MathContext;
28
import java.math.RoundingMode;
29
import java.text.DateFormat;
30
import java.util.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 org.gvsig.json.Json;
38
import javax.json.JsonObject;
39
import org.gvsig.json.JsonObjectBuilder;
40
import org.apache.commons.lang3.ArrayUtils;
41
import org.apache.commons.lang3.ObjectUtils;
42
import org.apache.commons.lang3.StringUtils;
43
import org.apache.commons.lang3.tuple.Pair;
44
import org.cresques.cts.IProjection;
45
import org.gvsig.expressionevaluator.Expression;
46
import org.gvsig.expressionevaluator.ExpressionUtils;
47
import org.gvsig.fmap.crs.CRSFactory;
48
import org.gvsig.fmap.dal.DALLocator;
49
import org.gvsig.fmap.dal.DataStore;
50
import org.gvsig.fmap.dal.DataTypes;
51
import org.gvsig.fmap.dal.expressionevaluator.FeatureAttributeEmulatorExpression;
52
import org.gvsig.fmap.dal.feature.DataProfile;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.feature.FeatureType;
59
import org.gvsig.fmap.dal.feature.ForeingKey;
60
import org.gvsig.fmap.geom.Geometry;
61
import org.gvsig.fmap.geom.GeometryException;
62
import org.gvsig.fmap.geom.GeometryLocator;
63
import org.gvsig.fmap.geom.GeometryUtils;
64
import org.gvsig.fmap.geom.type.GeometryType;
65
import org.gvsig.json.JsonManager;
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.CoercionException;
73
import org.gvsig.tools.dataTypes.DataType;
74
import org.gvsig.tools.dataTypes.DataTypeUtils;
75
import org.gvsig.tools.dynobject.DynField;
76
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
77
import org.gvsig.tools.dynobject.DynField_v2;
78
import org.gvsig.tools.dynobject.DynMethod;
79
import org.gvsig.tools.dynobject.DynObject;
80
import org.gvsig.tools.dynobject.DynObjectValueItem;
81
import org.gvsig.tools.dynobject.DynStruct;
82
import org.gvsig.tools.dynobject.Tags;
83
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
84
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
85
import org.gvsig.tools.dynobject.exception.DynMethodException;
86
import org.gvsig.tools.dynobject.impl.DefaultTags;
87
import org.gvsig.tools.evaluator.AbstractEvaluator;
88
import org.gvsig.tools.evaluator.Evaluator;
89
import org.gvsig.tools.evaluator.EvaluatorData;
90
import org.gvsig.tools.evaluator.EvaluatorException;
91
import org.gvsig.tools.i18n.I18nManager;
92
import org.gvsig.tools.persistence.PersistenceManager;
93
import org.gvsig.tools.persistence.Persistent;
94
import org.gvsig.tools.persistence.PersistentState;
95
import org.gvsig.tools.persistence.exception.PersistenceException;
96
import org.slf4j.Logger;
97
import org.slf4j.LoggerFactory;
98
import org.gvsig.tools.dataTypes.CoercionContext;
99
import org.gvsig.tools.dataTypes.DataType.NumberPrecisionAndScale;
100
import org.gvsig.tools.util.GetItemWithSize;
101
import org.gvsig.tools.util.LabeledValue;
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 Evaluator getEvaluator() {
379
    return this.evaluator;
380
  }
381

    
382
  @Override
383
  public int getGeometryType() {
384
    if (this.dataType.getType() != DataTypes.GEOMETRY) {
385
      return Geometry.TYPES.UNKNOWN;
386
    }
387
    return this.geometryType;
388
  }
389

    
390
  @Override
391
  public int getGeometrySubType() {
392
    if (this.dataType.getType() != DataTypes.GEOMETRY) {
393
      return Geometry.SUBTYPES.UNKNOWN;
394
    }
395
    return this.geometrySubType;
396
  }
397

    
398
  @Override
399
  public GeometryType getGeomType() {
400
    if (this.dataType.getType() != DataTypes.GEOMETRY) {
401
      return null;
402
    }
403
    if (this.geomType == null) {
404
      try {
405
        this.geomType
406
                = GeometryLocator.getGeometryManager().getGeometryType(
407
                        this.geometryType, this.geometrySubType);
408
      } catch (GeometryException e) {
409
        throw new RuntimeException(
410
                "Error getting geometry type with type = "
411
                + this.geometryType + ", subtype = "
412
                + this.geometrySubType, e);
413
      }
414
    }
415
    return this.geomType;
416
  }
417

    
418
  @Override
419
  public int getIndex() {
420
    return this.index;
421
  }
422

    
423
  protected FeatureAttributeDescriptor setIndex(int index) {
424
    this.index = index;
425
    return this;
426
  }
427

    
428
  @Override
429
  public int getMaximumOccurrences() {
430
    return this.maximumOccurrences;
431
  }
432

    
433
  @Override
434
  public int getMinimumOccurrences() {
435
    return this.minimumOccurrences;
436
  }
437

    
438
  @Override
439
  public String getName() {
440
    return this.name;
441
  }
442

    
443
  public FeatureAttributeDescriptor setName(String name) {
444
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] set name [%s].", this.hashCode(), name));
445
    this.name = name;
446
    return this;
447
  }
448

    
449
  @Override
450
  public Class getObjectClass() {
451
    if (getDataType().getType() == DataTypes.OBJECT) {
452
      return objectClass;
453
    }
454
    return getDataType().getDefaultClass();
455
  }
456

    
457
  @Override
458
  public int getPrecision() {
459
    return this.precision;
460
  }
461

    
462
  @Override
463
  public int getScale() {
464
    return this.scale;
465
  }
466

    
467
  @Override
468
  public Coercion getCoercion() {
469
    return this.getDataType().getCoercion();
470
  }
471

    
472
  @Override
473
  public MathContext getMathContext() {
474
    if (this.mathContext == null) {
475
      if (this.getDataType().isNumeric()) {
476
        this.mathContext = new MathContext(
477
                this.getPrecision(),
478
                RoundingMode.valueOf(this.getRoundMode())
479
        );
480
      } else {
481
        this.mathContext = MathContext.UNLIMITED;
482
      }
483
    }
484
    return this.mathContext;
485
  }
486

    
487
  @Override
488
  public CoercionContext getCoercionContext() {
489
    if (this.coerceContext == null) {
490
      if (this.getDataType().isNumeric()) {
491
        this.coerceContext = DataTypeUtils.coerceContextDecimal(
492
                this.getLocale(),
493
                this.getPrecision(),
494
                this.getScale(),
495
                this.getRoundMode()
496
        );
497
      } else {
498
        this.coerceContext = DataTypeUtils.coerceContextLocale(
499
                this.getLocale()
500
        );
501
      }
502
    }
503
    return this.coerceContext;
504
  }
505

    
506
  @Override
507
  public int getRoundMode() {
508
    return this.roundMode;
509
  }
510

    
511
  @Override
512
  public IProjection getSRS() {
513
    return this.SRS;
514
  }
515

    
516
  @Override
517
  public Interval getInterval() {
518
    return this.interval;
519
  }
520

    
521
  public IProjection getSRS(WeakReference storeRef) {
522
    if (this.SRS == null) {
523
      FeatureStore store = (FeatureStore) storeRef.get();
524
      this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
525
    }
526
    return this.SRS;
527
  }
528

    
529
  @Override
530
  public int getSize() {
531
    return this.size;
532
  }
533

    
534
  @Override
535
  public boolean isPrimaryKey() {
536
    return this.primaryKey;
537
  }
538

    
539
  @Override
540
  public boolean isReadOnly() {
541
    if (this.readOnly) {
542
      return true;
543
    }
544
    return this.isComputed();
545
  }
546

    
547
  @Override
548
  public String getAdditionalInfo(String infoName) {
549
    if (this.additionalInfo == null) {
550
      return null;
551
    }
552
    return this.additionalInfo.get(infoName);
553
  }
554

    
555
  @Override
556
  public boolean isAutomatic() {
557
    return this.isAutomatic;
558
  }
559

    
560
  @Override
561
  public boolean equals(Object obj) {
562
    if (this == obj) {
563
      return true;
564
    }
565
    if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
566
      return false;
567
    }
568
    DefaultFeatureAttributeDescriptor other
569
            = (DefaultFeatureAttributeDescriptor) obj;
570

    
571
    if (this.allowNull != other.allowNull) {
572
      return false;
573
    }
574

    
575
    if (this.index != other.index) {
576
      return false;
577
    }
578

    
579
    if (!Objects.equals(this.name, other.name)) {
580
      return false;
581
    }
582

    
583
    if (this.getDataType() != other.getDataType()) {
584
      return false;
585
    }
586

    
587
    if (this.size != other.size) {
588
      return false;
589
    }
590

    
591
    if (!Objects.equals(this.defaultValue, other.defaultValue)) {
592
      return false;
593
    }
594

    
595
    if (this.primaryKey != other.primaryKey) {
596
      return false;
597
    }
598

    
599
    if (this.isAutomatic != other.isAutomatic) {
600
      return false;
601
    }
602

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

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

    
611
    if (this.maximumOccurrences != other.maximumOccurrences) {
612
      return false;
613
    }
614

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

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

    
623
    if (this.geometrySubType != other.geometrySubType) {
624
      return false;
625
    }
626

    
627
    if (!Objects.equals(this.evaluator, other.evaluator)) {
628
      return false;
629
    }
630

    
631
    if (!Objects.equals(this.featureAttributeEmulator, other.featureAttributeEmulator)) {
632
      return false;
633
    }
634

    
635
    if (!Objects.equals(this.SRS, other.SRS)) {
636
      return false;
637
    }
638

    
639
    if (!Objects.equals(this.dateFormat, other.dateFormat)) {
640
      return false;
641
    }
642

    
643
    if (!Objects.equals(this.objectClass, other.objectClass)) {
644
      return false;
645
    }
646

    
647
    if (!Objects.equals(this.dataProfile, other.dataProfile)) {
648
      return false;
649
    }
650

    
651
    return true;
652
  }
653

    
654
  @Override
655
  public void loadFromState(PersistentState state)
656
          throws PersistenceException {
657
    allowNull = state.getBoolean("allowNull");
658
    dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
659
    dataProfile = state.getString("dataProfile");
660

    
661
//        FIXME: dateFormat;
662
    try {
663
      defaultValue = dataType.coerce(state.get("defaultValue"));
664
    } catch (CoercionException ex) {
665
    }
666

    
667
    index = state.getInt("index");
668
    maximumOccurrences = state.getInt("maximumOccurrences");
669
    minimumOccurrences = state.getInt("minimumOccurrences");
670
    size = state.getInt("size");
671
    name = state.getString("name");
672
    try {
673
      String objectClassName = state.getString("objectClass");
674
      if (!StringUtils.isBlank(objectClassName)) {
675
        objectClass = Class.forName(objectClassName);
676
      }
677
    } catch (Throwable e) {
678
      LOGGER.warn("Can't restore the objectClass of the FeatureAttributreDescriptor", e);
679
    }
680
    precision = state.getInt("precision");
681
    scale = state.getInt("scale");
682
    roundMode = state.getInt("roundMode");
683
    String locale_s = state.getString("locale");
684
    locale = StringUtils.isBlank(locale_s) ? null : Locale.forLanguageTag(locale_s); // || "null".equalsIgnoreCase(locale_s)
685
    evaluator = (Evaluator) state.get("evaluator");
686
    primaryKey = state.getBoolean("primaryKey");
687
    readOnly = state.getBoolean("readOnly");
688
    SRS = (IProjection) state.get("SRS");
689
    geometryType = state.getInt("geometryType");
690
    geometrySubType = state.getInt("geometrySubType");
691
    if (geometryType != Geometry.TYPES.UNKNOWN
692
            && geometrySubType != Geometry.SUBTYPES.UNKNOWN) {
693
      geomType = GeometryUtils.getGeometryType(
694
              geometryType,
695
              geometrySubType
696
      );
697
    }
698
//        additionalInfo = (Map) state.get("aditionalInfo");
699
    isAutomatic = state.getBoolean("isAutomatic");
700
    isTime = state.getBoolean("isTime");
701
    if (state.hasValue("intervalStart")) {
702
      long intervalStart = state.getLong("interval_start");
703
      long intervalEnd = state.getLong("interval_end");
704
      interval = TimeSupportLocator.getManager().createRelativeInterval(intervalStart, intervalEnd);
705
    } else {
706
      interval = null;
707
    }
708
    featureAttributeEmulator = (FeatureAttributeEmulator) state.get("featureAttributeEmulator");
709
    indexed = state.getBoolean("indexed");
710
    isIndexAscending = state.getBoolean("isIndexAscending");
711
    allowIndexDuplicateds = state.getBoolean("allowIndexDuplicateds");
712

    
713
    Map<String, Object> values = state.getMap("availableValues");
714
    if (values == null || values.isEmpty()) {
715
      this.availableValues = null;
716
    } else {
717
      this.availableValues = new DynObjectValueItem[values.size()];
718
      int n = 0;
719
      for (Entry<String, Object> entry : values.entrySet()) {
720
        this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
721
      }
722
    }
723

    
724
    description = state.getString("description");
725
    minValue = state.get("minValue");
726
    maxValue = state.get("maxValue");
727
    label = state.getString("label");
728
    order = state.getInt("order");
729
    hidden = state.getBoolean("hidden");
730
    groupName = state.getString("groupName");
731
    relationType = state.getInt("relationType", RELATION_TYPE_NONE);
732

    
733
    foreingKey = (DefaultForeingKey) state.get("foreingKey");
734
    if (foreingKey != null) {
735
      this.foreingKey.setDescriptor(this);
736
    }
737
    tags = (Tags) state.get("tags");
738
    if (tags == null) {
739
      this.tags = new DefaultTags();
740
    }
741
    displaySize = state.getInt("displaySize",0);
742
    availableValuesExpression = (Expression) state.get("availableValuesExpression");
743
    avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues",false);
744
    availableValuesCache = null;
745
    
746
  }
747

    
748
  @Override
749
  public void saveToState(PersistentState state) throws PersistenceException {
750
    Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
751
    
752
    state.set("allowNull", allowNull);
753
    state.set("dataType", dataType.getType());
754
    state.set("dataProfile", dataProfile);
755

    
756
//        FIXME: dateFormat;
757
    state.set("defaultValue", Objects.toString(defaultValue, null));
758

    
759
    state.set("index", index);
760
    state.set("maximumOccurrences", maximumOccurrences);
761
    state.set("minimumOccurrences", minimumOccurrences);
762
    state.set("size", size);
763
    state.set("name", name);
764
    state.set("objectClass", objectClass == null ? null : objectClass.getName());
765
    state.set("precision", precision);
766
    state.set("scale", scale);
767
    state.set("roundMode", roundMode);    
768
    if( this.locale == null ) {
769
      state.setNull("locale");
770
    } else {
771
      state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
772
    }
773
    state.set("evaluator", evaluator);
774

    
775
    state.set("primaryKey", primaryKey);
776
    state.set("readOnly", readOnly);
777
    state.set("SRS", SRS);
778
    GeometryType theGeomType = this.getGeomType();
779
    if (theGeomType == null) {
780
      state.set("geometryType", Geometry.TYPES.UNKNOWN);
781
      state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
782
    } else {
783
      state.set("geometryType", theGeomType.getType());
784
      state.set("geometrySubType", theGeomType.getSubType());
785
    }
786

    
787
//      FIXME: additionalInfo
788
    state.set("isAutomatic", isAutomatic);
789
    state.set("isTime", isTime);
790
    if (this.interval == null) {
791
      state.setNull("interval_start");
792
      state.setNull("interval_end");
793
    } else {
794
      state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
795
      state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
796
    }
797
    state.set("SRS", SRS);
798

    
799
//      FIXME: featureAttributeGetter
800
    if (featureAttributeEmulator instanceof Persistent) {
801
      state.set("featureAttributeEmulator", featureAttributeEmulator);
802
    } else {
803
      state.setNull("featureAttributeEmulator");
804
    }
805

    
806
    state.set("indexed", indexed);
807
    state.set("isIndexAscending", isIndexAscending);
808
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
809

    
810
    if (this.availableValues == null) {
811
      state.setNull("availableValues");
812
    } else {
813
      Map<String, Object> values = new LinkedHashMap<>();
814
      for (DynObjectValueItem value : availableValues) {
815
        values.put(value.getLabel(), value.getValue());
816
      }
817
      state.set("availableValues", values);
818
    }
819
    state.set("description", description);
820
    state.set("minValue", minValue);
821
    state.set("maxValue", maxValue);
822
    state.set("label", label);
823
    state.set("order", order);
824
    state.set("hidden", hidden);
825
    state.set("groupName", groupName);
826
    state.set("relationType", relationType);
827

    
828
    state.set("foreingKey", this.foreingKey);
829
    state.set("tags", this.tags);
830

    
831
    state.set("displaySize", displaySize);
832
    state.set("availableValuesExpression", availableValuesExpression);
833
    state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);    
834
  }
835

    
836
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
837

    
838
  public static void registerPersistenceDefinition() {
839
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
840

    
841
    if (manager.getDefinition(FEATATTRDESC_PERSISTENCE_DEFINITION_NAME)
842
            == null) {
843
      DynStruct definition = manager.addDefinition(DefaultFeatureAttributeDescriptor.class,
844
              FEATATTRDESC_PERSISTENCE_DEFINITION_NAME,
845
              FEATATTRDESC_PERSISTENCE_DEFINITION_NAME
846
              + " persistent definition",
847
              null,
848
              null
849
      );
850
      definition.addDynFieldBoolean("allowNull");
851
      definition.addDynFieldInt("dataType");
852
      definition.addDynFieldString("dataProfile");
853
//            definition.addDynFieldString("dateFormat");
854
      definition.addDynFieldString("defaultValue");
855
      definition.addDynFieldInt("index");
856
      definition.addDynFieldInt("maximumOccurrences");
857
      definition.addDynFieldInt("minimumOccurrences");
858
      definition.addDynFieldInt("size");
859
      definition.addDynFieldString("name");
860
      definition.addDynFieldString("objectClass");
861
      definition.addDynFieldInt("precision");
862
      definition.addDynFieldInt("scale").setMandatory(false).setDefaultDynValue(DataType.SCALE_NONE);
863
      definition.addDynFieldInt("roundMode").setMandatory(false).setDefaultDynValue(BigDecimal.ROUND_HALF_UP);
864
      definition.addDynFieldString("locale").setMandatory(false).setDefaultDynValue("null");
865
      definition.addDynFieldObject("evaluator").setClassOfValue(Evaluator.class);
866
      definition.addDynFieldBoolean("primaryKey");
867
      definition.addDynFieldBoolean("readOnly");
868
      definition.addDynFieldObject("SRS")
869
              .setClassOfValue(IProjection.class);
870
      definition.addDynFieldInt("geometryType");
871
      definition.addDynFieldInt("geometrySubType");
872
//            definition.addDynFieldMap("additionalInfo");
873
      definition.addDynFieldBoolean("isAutomatic");
874
      definition.addDynFieldBoolean("isTime");
875
      definition.addDynFieldLong("interval_start");
876
      definition.addDynFieldLong("interval_end");
877
      definition.addDynFieldObject("featureAttributeEmulator")
878
              .setClassOfValue(FeatureAttributeEmulator.class);
879
      definition.addDynFieldBoolean("indexed");
880
      definition.addDynFieldBoolean("isIndexAscending");
881
      definition.addDynFieldBoolean("allowIndexDuplicateds");
882
      definition.addDynFieldMap("availableValues")
883
              .setClassOfItems(Object.class);
884
      definition.addDynFieldString("description");
885
      definition.addDynFieldObject("minValue");
886
      definition.addDynFieldObject("maxValue");
887
      definition.addDynFieldString("label");
888
      definition.addDynFieldInt("order");
889
      definition.addDynFieldBoolean("hidden");
890
      definition.addDynFieldBoolean("avoidCachingAvailableValues");
891
      definition.addDynFieldString("groupName");
892
      definition.addDynFieldInt("relationType");
893

    
894
      definition.addDynFieldObject("foreingKey")
895
              .setClassOfValue(DefaultForeingKey.class);
896

    
897
      definition.addDynFieldObject("tags")
898
              .setClassOfValue(Tags.class);
899

    
900
      definition.addDynFieldInt("displaySize").setMandatory(false);
901
      definition.addDynFieldObject("availableValuesExpression")
902
              .setClassOfValue(Expression.class)
903
              .setMandatory(false);
904
    }
905
  }
906

    
907
  /*
908
     * Start of DynField interface Implementation
909
     *
910
   */
911
  @Override
912
  public Tags getTags() {
913
    return tags;
914
  }
915

    
916
  @Override
917
  public boolean hasConstantAvailableValues() {
918
    return this.availableValues != null;
919
  }
920

    
921
  @Override
922
  public boolean isAvoidCachingAvailableValues() {
923
    return this.avoidCachingAvailableValues;
924
  }
925
  
926
  public boolean hasAvailableValues() {
927
      return getAvailableValues()!=null;
928
  }
929
  
930
  @Override
931
  public DynObjectValueItem[] getAvailableValues() {
932
    DynObjectValueItem[] values = this.availableValues;
933
    
934
    if (values != null) {
935
        return values;
936
    }
937
    values = this.availableValuesCache;
938
    if (values != null) {
939
        return values;
940
    }
941
    if (this.isForeingKey() && this.foreingKey.isClosedList()) {
942
      values = this.foreingKey.getAvailableValues(null);
943

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

    
1088
  private DynObjectValueItem[] getAvailableValuesFromExpression() {
1089
      if( this.availableValuesExpression == null || this.availableValuesExpression.isEmpty() ) {
1090
          return null;
1091
      }
1092
      try {
1093
        Object value = this.availableValuesExpression.execute(null);
1094
        if( value instanceof DynObjectValueItem[] ) {
1095
            return (DynObjectValueItem[]) value;
1096
        }
1097
        if( value instanceof List ) {
1098
            return this.getAvailableValuesFrom(new GetItemWithSize() {
1099
                @Override
1100
                public Object get(int i) {
1101
                    return ((List)value).get(i);
1102
                }
1103

    
1104
                @Override
1105
                public int size() {
1106
                    return ((List)value).size();
1107
                }
1108
            });
1109
        }
1110
      } catch(Throwable th) {
1111
          LOGGER.warn("Can't get available values from expression", th);
1112
      }
1113
      return null;
1114
  }
1115

    
1116
  @Override
1117
  public Expression getAvailableValuesExpression() {
1118
      return this.availableValuesExpression;
1119
  }
1120
  
1121
  @Override
1122
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1123
        if (StringUtils.isBlank(expression)) {
1124
            this.availableValuesExpression = null;
1125
            return this;
1126
        }
1127
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1128
        return this;
1129
    }
1130

    
1131
  @Override
1132
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1133
        this.availableValuesExpression = expression;
1134
        return this;
1135
    }
1136
  
1137
  @Override
1138
  public String getLabelOfValue(Object value) {
1139
    if (this.labelOfValueMap != null) {
1140
      String theLabel = this.labelOfValueMap.get(value);
1141
      if (theLabel == null) {
1142
        theLabel = Objects.toString(value, "");
1143
      }
1144
      return theLabel;
1145
    }
1146
    DynObjectValueItem[] values = this.getAvailableValues();
1147
    if (values == null) {
1148
      return Objects.toString(value, "");
1149
    }
1150
    Map<Object, String> map = new LinkedHashMap<>();
1151
    for (DynObjectValueItem theValue : values) {
1152
      map.put(theValue.getValue(), theValue.getLabel());
1153
    }
1154
    this.labelOfValueMap = map;
1155
    String theLabel = this.labelOfValueMap.get(value);
1156
    if (theLabel == null) {
1157
      theLabel = Objects.toString(value, "");
1158
    }
1159
    return theLabel;
1160
  }
1161

    
1162
  @Override
1163
  public String getDescription() {
1164
    if (this.description == null) {
1165
      return getName();
1166
    }
1167
    return this.description;
1168
  }
1169

    
1170
  @Override
1171
  public Object getMaxValue() {
1172
    return this.maxValue;
1173
  }
1174

    
1175
  @Override
1176
  public Object getMinValue() {
1177
    return this.minValue;
1178
  }
1179

    
1180
  @Override
1181
  public int getTheTypeOfAvailableValues() {
1182
    return 1;
1183
  }
1184

    
1185
  @Override
1186
  public int getType() {
1187
    if (featureAttributeGetter != null) {
1188
      return featureAttributeGetter.getDataType().getType();
1189
    }
1190
    return getDataType().getType();
1191
  }
1192

    
1193
  @Override
1194
  public boolean isMandatory() {
1195
    return !allowNull() || isPrimaryKey();
1196
  }
1197

    
1198
  @Override
1199
  public boolean isPersistent() {
1200
    return false;
1201
  }
1202

    
1203
  @Override
1204
  public DynField setAvailableValues(DynObjectValueItem[] values) {
1205
    if (ArrayUtils.isEmpty(values)) {
1206
      this.availableValues = null;
1207
    } else {
1208
      this.availableValues = values;
1209
    }
1210
    return this;
1211
  }
1212

    
1213
  @Override
1214
  public DynField setDescription(String description) {
1215
    this.description = description;
1216
    return this;
1217
  }
1218

    
1219
  @Override
1220
  public DynField setMandatory(boolean mandatory) {
1221
    throw new UnsupportedOperationException();
1222
  }
1223

    
1224
  @Override
1225
  public DynField setMaxValue(Object maxValue) {
1226
    try {
1227
      this.maxValue = this.coerce(maxValue);
1228
    } catch (CoercionException e) {
1229
      throw new IllegalArgumentException(e);
1230
    }
1231
    return this;
1232
  }
1233

    
1234
  @Override
1235
  public DynField setMinValue(Object minValue) {
1236
    try {
1237
      this.maxValue = this.coerce(minValue);
1238
    } catch (CoercionException e) {
1239
      throw new IllegalArgumentException(e);
1240
    }
1241
    return this;
1242
  }
1243

    
1244
  @Override
1245
  public DynField setPersistent(boolean persistent) {
1246
    throw new UnsupportedOperationException();
1247
  }
1248

    
1249
  @Override
1250
  public DynField setTheTypeOfAvailableValues(int type) {
1251
    throw new UnsupportedOperationException();
1252
  }
1253

    
1254
  @Override
1255
  public DynField setType(int type) {
1256
    throw new UnsupportedOperationException();
1257
  }
1258

    
1259
  @Override
1260
  @Deprecated
1261
  public DynField setDefaultDynValue(Object defaultValue) {
1262
    return this.setDefaultFieldValue(defaultValue);
1263
  }
1264

    
1265
  @Override
1266
  public DynField setDefaultFieldValue(Object defaultValue) {
1267
    this.defaultValue = defaultValue;
1268
    return this;
1269
  }
1270

    
1271
  @Override
1272
  public Class getClassOfValue() {
1273
    return null;
1274
  }
1275

    
1276
  @Override
1277
  public DynField getElementsType() {
1278
    return null;
1279
  }
1280

    
1281
  @Override
1282
  public DynField setClassOfValue(Class theClass)
1283
          throws DynFieldIsNotAContainerException {
1284
    throw new UnsupportedOperationException();
1285
  }
1286

    
1287
  @Override
1288
  public DynField setElementsType(DynStruct type)
1289
          throws DynFieldIsNotAContainerException {
1290
    throw new UnsupportedOperationException();
1291
  }
1292

    
1293
  @Override
1294
  public DynField setElementsType(int type)
1295
          throws DynFieldIsNotAContainerException {
1296
    throw new UnsupportedOperationException();
1297
  }
1298

    
1299
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1300
    this.dataProfile = dataProfile;
1301
    return this;
1302
  }
1303

    
1304
  @Override
1305
  public String getDataProfileName() {
1306
    return dataProfile;
1307
  }
1308

    
1309
  @Override
1310
  public DataProfile getDataProfile() {
1311
    if (StringUtils.isBlank(dataProfile)) {
1312
      return null;
1313
    }
1314
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1315
    return profile;
1316
  }
1317

    
1318
  @Override
1319
  public void validate(Object value) throws DynFieldValidateException {
1320

    
1321
    if (value == null && !this.allowNull()) {
1322
      throw new DynFieldValidateException(value, this, null);
1323
    }
1324

    
1325
    try {
1326
      this.dataType.coerce(value);
1327
    } catch (CoercionException e) {
1328
      throw new DynFieldValidateException(value, this, e);
1329
    }
1330

    
1331
    /*
1332
         * Other checks will be needed
1333
     */
1334
  }
1335

    
1336
  @Override
1337
  public String getSubtype() {
1338
    if (featureAttributeGetter != null) {
1339
      return featureAttributeGetter.getDataType().getSubtype();
1340
    }
1341
    return this.dataType.getSubtype();
1342
  }
1343

    
1344
  @Override
1345
  public Object coerce(Object value) throws CoercionException {
1346
    if (value == null) {
1347
      return value; // O debe devolver this.defaultValue
1348
    }
1349
    try {
1350
      return this.getDataType().coerce(value, this.getCoercionContext());
1351
    } catch (Exception ex) {
1352
      throw new RuntimeException(ex);
1353
    }
1354
  }
1355

    
1356
  @Override
1357
  public DynField setAvailableValues(List values) {
1358
    if (values == null || values.isEmpty()) {
1359
      this.availableValues = null;
1360
    } else {
1361
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1362
              new DynObjectValueItem[values.size()]
1363
      );
1364
    }
1365
    return this;
1366
  }
1367

    
1368
  @Override
1369
  public String getGroup() {
1370
    return this.groupName;
1371
  }
1372

    
1373
  @Override
1374
  public int getOder() {
1375
    return this.order;
1376
  }
1377

    
1378
  @Override
1379
  public String getLabel() {
1380
    if (this.label == null) {
1381
      return this.getName();
1382
    }
1383
    return this.label;
1384
  }
1385

    
1386
  @Override
1387
  public String getLocalizedLabel() {
1388
    if (StringUtils.isBlank(this.label)) {
1389
      return this.getName();
1390
    }
1391
    I18nManager i18n = ToolsLocator.getI18nManager();
1392
    return i18n.getTranslation(this.label);
1393
  }
1394

    
1395
  @Override
1396
  public DynField setLabel(String label) {
1397
    this.label = label;
1398
    return this;
1399
  }
1400

    
1401
  @Override
1402
  public DynField setShortLabel(String shortLabel) {
1403
    this.shortLabel = shortLabel;
1404
    return this;
1405
  }
1406

    
1407
  @Override
1408
  public String getShortLabel() {
1409
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1410
  }
1411

    
1412
  @Override
1413
  public String getLocalizedShortLabel() {
1414
    if (StringUtils.isBlank(shortLabel)) {
1415
      return this.getLocalizedLabel();
1416
    }
1417
    I18nManager i18n = ToolsLocator.getI18nManager();
1418
    return i18n.getTranslation(shortLabel);
1419
  }
1420

    
1421
  @Override
1422
  public DynField setGroup(String groupName) {
1423
    this.groupName = groupName;
1424
    return this;
1425
  }
1426

    
1427
  @Override
1428
  public DynField setOrder(int order) {
1429
    this.order = order;
1430
    return this;
1431
  }
1432

    
1433
  @Override
1434
  public DynField setHidden(boolean hidden) {
1435
    this.hidden = hidden;
1436
    return this;
1437
  }
1438

    
1439
  @Override
1440
  public boolean isHidden() {
1441
    return this.hidden;
1442
  }
1443

    
1444
  @Override
1445
  public DynField setReadOnly(boolean readOnly) {
1446
    this.readOnly = readOnly;
1447
    return this;
1448
  }
1449

    
1450
  @Override
1451
  public boolean isContainer() {
1452
    return false;
1453
  }
1454

    
1455
  @Override
1456
  public Class getClassOfItems() {
1457
    return null;
1458
  }
1459

    
1460
  @Override
1461
  public DynField setClassOfItems(Class theClass) {
1462
    throw new UnsupportedOperationException();
1463
  }
1464

    
1465
  @Override
1466
  public DynField setType(DataType type) {
1467
    throw new UnsupportedOperationException();
1468
  }
1469

    
1470
  @Override
1471
  public DynField setSubtype(String subtype) {
1472
    throw new UnsupportedOperationException();
1473
  }
1474

    
1475
  @Override
1476
  public boolean isTime() {
1477
    return isTime;
1478
  }
1479

    
1480
  @Override
1481
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1482
    return featureAttributeGetter;
1483
  }
1484

    
1485
  @Override
1486
  public void setFeatureAttributeGetter(
1487
          FeatureAttributeGetter featureAttributeTransform) {
1488
    this.featureAttributeGetter = featureAttributeTransform;
1489
  }
1490

    
1491
  @Override
1492
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1493
    return this.featureAttributeEmulator;
1494
  }
1495

    
1496
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1497
    this.featureAttributeEmulator = featureAttributeEmulator;
1498
    return this;
1499
  }
1500

    
1501
  @Override
1502
  public boolean isIndexed() {
1503
    return this.indexed;
1504
  }
1505

    
1506
  @Override
1507
  public boolean isForeingKey() {
1508
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1509
  }
1510

    
1511
  @Override
1512
  public ForeingKey getForeingKey() {
1513
    return this.foreingKey;
1514
  }
1515

    
1516
  @Override
1517
  public boolean allowIndexDuplicateds() {
1518
    return this.allowIndexDuplicateds;
1519
  }
1520

    
1521
  @Override
1522
  public boolean isIndexAscending() {
1523
    return this.isIndexAscending;
1524
  }
1525

    
1526
  @Override
1527
  public DynField setClassOfValue(DynStruct dynStrct) {
1528
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1529
  }
1530

    
1531
  @Override
1532
  public DynField setClassOfValue(String theClassNameOfValue) {
1533
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1534
  }
1535

    
1536
  @Override
1537
  public String getClassNameOfValue() {
1538
    return null;
1539
  }
1540

    
1541
  @Override
1542
  public DynStruct getDynClassOfValue() {
1543
    return null;
1544
  }
1545

    
1546
  @Override
1547
  public DynField setTypeOfItems(int type) {
1548
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1549
  }
1550

    
1551
  @Override
1552
  public int getTypeOfItems() {
1553
    return DataTypes.INVALID;
1554
  }
1555

    
1556
  @Override
1557
  public DynField setClassOfItems(DynStruct dynStrct) {
1558
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1559
  }
1560

    
1561
  @Override
1562
  public DynField setClassOfItems(String theClassNameOfValue) {
1563
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1564
  }
1565

    
1566
  @Override
1567
  public String getClassNameOfItems() {
1568
    return null;
1569
  }
1570

    
1571
  @Override
1572
  public DynStruct getDynClassOfItems() {
1573
    return null;
1574
  }
1575

    
1576
  @Override
1577
  public DynField setRelationType(int relationType) {
1578
    this.relationType = relationType;
1579
    return this;
1580
  }
1581

    
1582
  @Override
1583
  public int getRelationType() {
1584
    return this.relationType;
1585
  }
1586

    
1587
  @Override
1588
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1589
    this.availableValuesMethod = availableValuesMethod;
1590
    return this;
1591
  }
1592

    
1593
  @Override
1594
  public DynObjectValueItem[] getAvailableValues(DynObject self) {
1595
    if (this.availableValuesMethod != null) {
1596
      DynObjectValueItem[] values;
1597
      try {
1598
        values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self, new Object[]{this});
1599
      } catch (DynMethodException ex) {
1600
        return this.availableValues;
1601
      }
1602
      if (values != null) {
1603
        return values;
1604
      }
1605
    }
1606
    return this.availableValues;
1607
  }
1608

    
1609
  @Override
1610
  public DynMethod getAvailableValuesMethod() {
1611
    return this.availableValuesMethod;
1612
  }
1613

    
1614
  @Override
1615
  public boolean isAvailableValuesCalculated() {
1616
    return this.availableValuesMethod != null;
1617
  }
1618

    
1619
  @Override
1620
  public DynMethod getCalculateMethod() {
1621
    return this.calculateMethod;
1622
  }
1623

    
1624
  @Override
1625
  public DynField setCalculateMethod(DynMethod method) {
1626
    this.calculateMethod = method;
1627
    return this;
1628
  }
1629

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

    
1635
  @Override
1636
  public Object getCalculatedValue(DynObject self) {
1637
    try {
1638
      return this.calculateMethod.invoke(self, new Object[]{this});
1639
    } catch (DynMethodException ex) {
1640
      throw new RuntimeException(ex);
1641
    }
1642
  }
1643

    
1644
  @Override
1645
  public DynField setValidateElements(boolean validate) {
1646
    return this;
1647
  }
1648

    
1649
  @Override
1650
  public boolean getValidateElements() {
1651
    return false;
1652
  }
1653

    
1654
  @Override
1655
  public boolean hasLabel() {
1656
    return StringUtils.isNotBlank(this.label);
1657
  }
1658

    
1659
  @Override
1660
  public boolean hasShortLabel() {
1661
    return StringUtils.isNotBlank(this.shortLabel);
1662
  }
1663

    
1664
  @Override
1665
  public boolean hasDescription() {
1666
    return StringUtils.isNotBlank(this.description);
1667
  }
1668

    
1669
  @Override
1670
  public FeatureAttributeDescriptor getValue() {
1671
    return this;
1672
  }
1673

    
1674
  @Override
1675
  public int getDisplaySize() {
1676
    return this.displaySize;
1677
  }
1678

    
1679
    @Override
1680
    public boolean isInAvailableValues(Object valueToCheck) {
1681
        if (this.getAvailableValues()!=null) {
1682
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1683
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1684
                    return true;
1685
                }
1686
            }
1687
        }
1688
        return false;
1689
    }
1690

    
1691
  private class ConstantValueEvaluator extends AbstractEvaluator {
1692

    
1693
    @Override
1694
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1695
      return defaultValue;
1696
    }
1697

    
1698
    @Override
1699
    public String getName() {
1700
      return "Constant attribute " + name;
1701
    }
1702
  }
1703

    
1704
  public void setConstantValue(boolean isConstantValue) {
1705
    if (isConstantValue) {
1706
      /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1707
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1708
             * el evaluador el que se encarga de proporcionar su valor.
1709
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1710
             * por defecto para ese attributo.
1711
       */
1712
      this.evaluator = new ConstantValueEvaluator();
1713
    } else {
1714
      this.evaluator = null;
1715
    }
1716
  }
1717

    
1718
  @Override
1719
  public boolean isComputed() {
1720
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1721
  }
1722

    
1723
  @Override
1724
  public FeatureStore getStore() {
1725
    FeatureType ftype = this.getFeatureType();
1726
    if (ftype == null) {
1727
      return null;
1728
    }
1729
    return ftype.getStore();
1730
  }
1731

    
1732
  @Override
1733
  public FeatureType getFeatureType() {
1734
    if (this.typeRef == null) {
1735
      return null;
1736
    }
1737
    FeatureType ftype = (FeatureType) this.typeRef.get();
1738
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1739
    return ftype;
1740
  }
1741

    
1742
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1743
    this.interval = interval;
1744
    return this;
1745
  }
1746

    
1747
  public void fixAll() {
1748
    if (!this.getDataType().supportSize()) {
1749
      this.size = 0;
1750
    }
1751
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1752
    this.precision = ps.getPrecision();
1753
    this.scale = ps.getScale();
1754

    
1755
    switch (this.getType()) {
1756
      case DataTypes.INSTANT:
1757
      case DataTypes.INTERVAL:
1758
      case DataTypes.DATE:
1759
      case DataTypes.TIME:
1760
      case DataTypes.TIMESTAMP:
1761
        if (this.getInterval() != null) {
1762
          this.isTime = true;
1763
        }
1764
        break;
1765
    }
1766
  }
1767

    
1768
  @Override
1769
  public String[] getRequiredFieldNames() {
1770
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1771
    if (emulator == null) {
1772
      return null;
1773
    }
1774
    return emulator.getRequiredFieldNames();
1775
  }
1776

    
1777
  @Override
1778
  public void recentUsed() {
1779
    DefaultFeatureType.RECENTS_USEDS.add(this);
1780
  }
1781

    
1782
  @Override
1783
  public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1784
    if (other == null) {
1785
      throw new NullPointerException();
1786
    }
1787
    DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1788
    if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1789
      return false;
1790
    }
1791
    if (old.isComputed() && old.isComputed() == this.isComputed()) {
1792
      return true;
1793
    }
1794
    if (this.dataType != old.dataType) {
1795
      return false;
1796
    }
1797
    if (this.size != old.size) {
1798
      return false;
1799
    }
1800
    if (this.precision != old.precision) {
1801
      return false;
1802
    }
1803
//        if( this.primaryKey != old.primaryKey ) {
1804
//            return false;
1805
//        }
1806
    if (this.geomType != old.geomType) {
1807
      return false;
1808
    }
1809
    if (this.SRS != old.SRS) {
1810
      return false;
1811
    }
1812
    if (this.isAutomatic != old.isAutomatic) {
1813
      return false;
1814
    }
1815
    return true;
1816
  }
1817
  
1818
  private class PropertiesBuilder {
1819

    
1820
        private String name;
1821
        private DataType type;
1822
        private Map<String,String> sets;
1823
        private String sep;
1824
      
1825
      public PropertiesBuilder() {
1826
          this.sets = new LinkedHashMap<>();
1827
      }
1828
      
1829
      public void separator(String sep) {
1830
          this.sep = sep;
1831
      }
1832
      
1833
      public void name(String name) {
1834
        this.name = name;
1835
      }
1836
      
1837
      public void type(DataType type) {
1838
          this.type = type;
1839
      }
1840
      
1841
      public void set(String name, ForeingKey fk) {
1842
          if( fk == null ) {
1843
              return;
1844
          }
1845
          if( !fk.isForeingKey() ) {
1846
              return;
1847
          }
1848
          this.set(name, fk.isForeingKey());
1849
          this.set(name+"_code", fk.getCodeName());
1850
          this.set(name+"_label", fk.getLabelFormula());
1851
          this.set(name+"_closedlist", fk.isClosedList());
1852
          this.set(name+"_table", fk.getTableName());
1853
      }
1854

    
1855
      public void set(String name, FeatureAttributeEmulator value) {
1856
          if( value == null ) {
1857
              return;
1858
          }
1859
          if( value instanceof FeatureAttributeEmulatorExpression ) {
1860
            this.set(name, ((FeatureAttributeEmulatorExpression)value).getExpression().getPhrase());
1861
          }
1862
      }
1863
      
1864
      public void set(String name, IProjection value) {
1865
          if( value == null ) {
1866
              return;
1867
          }
1868
          this.set(name, value.getAbrev());
1869
      }
1870
      
1871
      public void set(String name, GeometryType value) {
1872
          if( value == null ) {
1873
              return;
1874
          }
1875
          this.set(name, value.getFullName().replace(":", "@"));
1876
      }
1877
      
1878
      public void set(String name, Object value) {
1879
          if( value == null ) {
1880
              return;
1881
          }
1882
          String s = Objects.toString(value, "");
1883
          if( StringUtils.isBlank(s) ) {
1884
              return;
1885
          }
1886
          this.sets.put(name, s);
1887
      }
1888
      
1889
      public void set(String name, Object value, Object skipValue) {
1890
          if( value == null || value == skipValue) {
1891
              return;
1892
          }
1893
          String s = Objects.toString(value, "");
1894
          if( StringUtils.isBlank(s) ) {
1895
              return;
1896
          }
1897
          this.sets.put(name, s);
1898
      }
1899
      
1900
      @Override
1901
      public String toString() {        
1902
        StringBuilder builder = new StringBuilder();
1903
        builder.append(this.name);
1904
        builder.append(sep);        
1905
        builder.append(this.type.getName());
1906
        for (String key : this.sets.keySet()) {
1907
            builder.append(sep);        
1908
            builder.append("set");
1909
            builder.append(sep);        
1910
            builder.append(key);        
1911
            builder.append("=");        
1912
            builder.append(this.sets.get(key));                    
1913
        }
1914
        return builder.toString();
1915
      }
1916
  }
1917

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

    
2083
    @Override
2084
    public JsonObjectBuilder toJsonBuilder() {
2085
        JsonObjectBuilder builder = Json.createObjectBuilder();
2086
        builder.add_class(this);
2087
        builder.add("name", this.name);
2088
        builder.add("description", this.description);
2089
        builder.add("label", this.label);
2090
        builder.add("shortLabel", this.shortLabel);
2091
        builder.add("order", this.order);
2092
        builder.add("groupName", this.groupName);
2093
        builder.add("dataType", this.dataType);
2094
        builder.add("size", this.size);
2095
        builder.add("precision", this.precision);
2096
        builder.add("scale", this.scale);
2097
        builder.add("roundMode", this.roundMode);
2098

    
2099
        builder.add("allowNull", this.allowNull);
2100
        builder.add("primaryKey", this.primaryKey);
2101
        builder.add("readOnly", this.readOnly);
2102
        builder.add("isAutomatic", this.isAutomatic);
2103
        builder.add("isTime", this.isTime);
2104
        builder.add("indexed", this.indexed);
2105
        builder.add("isIndexAscending", this.isIndexAscending);
2106
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2107
        builder.add("hidden", this.hidden);
2108
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2109

    
2110
        builder.add("geometryType",this.getGeomType());
2111
        builder.add("srs", this.getSRS());
2112

    
2113
        builder.add("relationType", this.relationType);
2114
        builder.add("displaySize", this.displaySize);
2115
        builder.add("locale", this.getLocale());
2116
        builder.add("expression", this.getFeatureAttributeEmulator());
2117
        if( this.isForeingKey() ) {
2118
            builder.add("fk", this.isForeingKey());
2119
            builder.add("fk_table", this.getForeingKey().getTableName());
2120
            builder.add("fk_code", this.getForeingKey().getCodeName());
2121
            builder.add("fk_label", this.getForeingKey().getLabelFormula());
2122
            builder.add("fk_closedlist", this.getForeingKey().isClosedList());
2123
        }
2124
        builder.add("availableValuesExpression", this.availableValuesExpression);
2125
        builder.add("defaultValue", Objects.toString(this.defaultValue,""));
2126
        builder.add("dataProfile", this.getDataProfileName());
2127
        builder.add("tags", tags);
2128
        builder.add("availableValues", availableValues);
2129
        builder.add("additionalInfo", this.additionalInfo);
2130
        return builder;
2131
    }
2132
    
2133
    public void fromJson(JsonObject json) {
2134
        this.name = json.getString("name");
2135
        this.description = json.getString("description");
2136
        this.label = json.getString("label");
2137
        this.shortLabel = json.getString("shortLabel");
2138
        this.order = json.getInt("order");
2139
        this.groupName = json.getString("groupName");
2140
        this.precision = json.getInt("precision");
2141
        this.size = json.getInt("size");
2142
        this.scale = json.getInt("scale");
2143
        this.roundMode = json.getInt("roundMode");
2144
        
2145
        this.allowNull = json.getBoolean("allowNull");       
2146
        this.primaryKey = json.getBoolean("primaryKey");
2147
        this.readOnly = json.getBoolean("readOnly");
2148
        this.isAutomatic = json.getBoolean("isAutomatic");
2149
        this.isTime = json.getBoolean("isTime");
2150
        this.indexed = json.getBoolean("indexed");
2151
        this.isIndexAscending = json.getBoolean("isIndexAscending");
2152
        this.allowIndexDuplicateds = json.getBoolean("allowIndexDuplicateds");
2153
        this.hidden = json.getBoolean("hidden");
2154
        this.avoidCachingAvailableValues = json.getBoolean("avoidCachingAvailableValues");
2155

    
2156
        this.relationType = json.getInt("relationType");
2157
        this.displaySize = json.getInt("displaySize");
2158

    
2159
        this.dataType = (DataType) Json.toObject(json,"dataType");
2160
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2161
        this.SRS = (IProjection) Json.toObject(json, "srs");
2162
        this.locale = (Locale) Json.toObject(json, "locale");
2163
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json,"expression");
2164

    
2165
        this.tags = (Tags) Json.toObject(json, "tags");
2166
        this.additionalInfo = Json.toHashMap(json, "additionalInfo");
2167
        this.availableValues = (DynObjectValueItem[]) Json.toArray(json, "availableValues", new DynObjectValueItem[0]);
2168
        this.dataProfile = json.getString("dataProfile", null);
2169
        try {
2170
            this.defaultValue = this.coerce(json.getString("defaultValue", null));
2171
        } catch(Exception ex) {
2172
            LOGGER.warn("Can't retrive default value for attribute '"+this.name+"'.",ex);
2173
        }
2174
        this.availableValuesExpression = (Expression) Json.toObject(json,"availableValuesExpression");
2175
        if( json.getBoolean("fk", false) ) {
2176
            this.foreingKey = new DefaultForeingKey();
2177
            this.foreingKey.setTableName(json.getString("fk_table", null));
2178
            this.foreingKey.setCodeName(json.getString("fk_code", null));
2179
            this.foreingKey.setLabelFormula(json.getString("fk_label", null));
2180
            this.foreingKey.setClosedList(json.getBoolean("fk_closedlist", false));
2181
        }
2182
    }
2183
    
2184
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
2185
        
2186
        public TheJsonSerializer() {            
2187
        }
2188

    
2189
        @Override
2190
        public Class getObjectClass() {
2191
            return DefaultFeatureAttributeDescriptor.class;
2192
        }
2193

    
2194
        @Override
2195
        public Object toObject(JsonObject json) {
2196
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2197
            o.fromJson(json);
2198
            return o;
2199
        }
2200

    
2201
        @Override
2202
        public JsonObjectBuilder toJsonBuilder(Object value) {
2203
            return ((SupportToJson)value).toJsonBuilder();
2204
        }
2205
        
2206
    }
2207

    
2208
    public static void selfRegister() {
2209
        Json.registerSerializer(new TheJsonSerializer());
2210
    }
2211

    
2212
}