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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
376
  @Override
377
  public Evaluator getEvaluator() {
378
    return this.evaluator;
379
  }
380

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
650
    return true;
651
  }
652

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1258
  @Override
1259
  public DynField setDefaultDynValue(Object defaultValue) {
1260
    throw new UnsupportedOperationException();
1261
  }
1262

    
1263
  @Override
1264
  public Class getClassOfValue() {
1265
    return null;
1266
  }
1267

    
1268
  @Override
1269
  public DynField getElementsType() {
1270
    return null;
1271
  }
1272

    
1273
  @Override
1274
  public DynField setClassOfValue(Class theClass)
1275
          throws DynFieldIsNotAContainerException {
1276
    throw new UnsupportedOperationException();
1277
  }
1278

    
1279
  @Override
1280
  public DynField setElementsType(DynStruct type)
1281
          throws DynFieldIsNotAContainerException {
1282
    throw new UnsupportedOperationException();
1283
  }
1284

    
1285
  @Override
1286
  public DynField setElementsType(int type)
1287
          throws DynFieldIsNotAContainerException {
1288
    throw new UnsupportedOperationException();
1289
  }
1290

    
1291
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1292
    this.dataProfile = dataProfile;
1293
    return this;
1294
  }
1295

    
1296
  @Override
1297
  public String getDataProfileName() {
1298
    return dataProfile;
1299
  }
1300

    
1301
  @Override
1302
  public DataProfile getDataProfile() {
1303
    if (StringUtils.isBlank(dataProfile)) {
1304
      return null;
1305
    }
1306
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1307
    return profile;
1308
  }
1309

    
1310
  @Override
1311
  public void validate(Object value) throws DynFieldValidateException {
1312

    
1313
    if (value == null && !this.allowNull()) {
1314
      throw new DynFieldValidateException(value, this, null);
1315
    }
1316

    
1317
    try {
1318
      this.dataType.coerce(value);
1319
    } catch (CoercionException e) {
1320
      throw new DynFieldValidateException(value, this, e);
1321
    }
1322

    
1323
    /*
1324
         * Other checks will be needed
1325
     */
1326
  }
1327

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

    
1336
  @Override
1337
  public Object coerce(Object value) throws CoercionException {
1338
    if (value == null) {
1339
      return value; // O debe devolver this.defaultValue
1340
    }
1341
    try {
1342
      return this.getDataType().coerce(value, this.getCoercionContext());
1343
    } catch (Exception ex) {
1344
      throw new RuntimeException(ex);
1345
    }
1346
  }
1347

    
1348
  @Override
1349
  public DynField setAvailableValues(List values) {
1350
    if (values == null || values.isEmpty()) {
1351
      this.availableValues = null;
1352
    } else {
1353
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1354
              new DynObjectValueItem[values.size()]
1355
      );
1356
    }
1357
    return this;
1358
  }
1359

    
1360
  @Override
1361
  public String getGroup() {
1362
    return this.groupName;
1363
  }
1364

    
1365
  @Override
1366
  public int getOder() {
1367
    return this.order;
1368
  }
1369

    
1370
  @Override
1371
  public String getLabel() {
1372
    if (this.label == null) {
1373
      return this.getName();
1374
    }
1375
    return this.label;
1376
  }
1377

    
1378
  @Override
1379
  public String getLocalizedLabel() {
1380
    if (StringUtils.isBlank(this.label)) {
1381
      return this.getName();
1382
    }
1383
    I18nManager i18n = ToolsLocator.getI18nManager();
1384
    return i18n.getTranslation(this.label);
1385
  }
1386

    
1387
  @Override
1388
  public DynField setLabel(String label) {
1389
    this.label = label;
1390
    return this;
1391
  }
1392

    
1393
  @Override
1394
  public DynField setShortLabel(String shortLabel) {
1395
    this.shortLabel = shortLabel;
1396
    return this;
1397
  }
1398

    
1399
  @Override
1400
  public String getShortLabel() {
1401
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1402
  }
1403

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

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

    
1419
  @Override
1420
  public DynField setOrder(int order) {
1421
    this.order = order;
1422
    return this;
1423
  }
1424

    
1425
  @Override
1426
  public DynField setHidden(boolean hidden) {
1427
    this.hidden = hidden;
1428
    return this;
1429
  }
1430

    
1431
  @Override
1432
  public boolean isHidden() {
1433
    return this.hidden;
1434
  }
1435

    
1436
  @Override
1437
  public DynField setReadOnly(boolean readOnly) {
1438
    this.readOnly = readOnly;
1439
    return this;
1440
  }
1441

    
1442
  @Override
1443
  public boolean isContainer() {
1444
    return false;
1445
  }
1446

    
1447
  @Override
1448
  public Class getClassOfItems() {
1449
    return null;
1450
  }
1451

    
1452
  @Override
1453
  public DynField setDefaultFieldValue(Object defaultValue) {
1454
    throw new UnsupportedOperationException();
1455
  }
1456

    
1457
  @Override
1458
  public DynField setClassOfItems(Class theClass) {
1459
    throw new UnsupportedOperationException();
1460
  }
1461

    
1462
  @Override
1463
  public DynField setType(DataType type) {
1464
    throw new UnsupportedOperationException();
1465
  }
1466

    
1467
  @Override
1468
  public DynField setSubtype(String subtype) {
1469
    throw new UnsupportedOperationException();
1470
  }
1471

    
1472
  @Override
1473
  public boolean isTime() {
1474
    return isTime;
1475
  }
1476

    
1477
  @Override
1478
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1479
    return featureAttributeGetter;
1480
  }
1481

    
1482
  @Override
1483
  public void setFeatureAttributeGetter(
1484
          FeatureAttributeGetter featureAttributeTransform) {
1485
    this.featureAttributeGetter = featureAttributeTransform;
1486
  }
1487

    
1488
  @Override
1489
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1490
    return this.featureAttributeEmulator;
1491
  }
1492

    
1493
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1494
    this.featureAttributeEmulator = featureAttributeEmulator;
1495
    return this;
1496
  }
1497

    
1498
  @Override
1499
  public boolean isIndexed() {
1500
    return this.indexed;
1501
  }
1502

    
1503
  @Override
1504
  public boolean isForeingKey() {
1505
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1506
  }
1507

    
1508
  @Override
1509
  public ForeingKey getForeingKey() {
1510
    return this.foreingKey;
1511
  }
1512

    
1513
  @Override
1514
  public boolean allowIndexDuplicateds() {
1515
    return this.allowIndexDuplicateds;
1516
  }
1517

    
1518
  @Override
1519
  public boolean isIndexAscending() {
1520
    return this.isIndexAscending;
1521
  }
1522

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

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

    
1533
  @Override
1534
  public String getClassNameOfValue() {
1535
    return null;
1536
  }
1537

    
1538
  @Override
1539
  public DynStruct getDynClassOfValue() {
1540
    return null;
1541
  }
1542

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

    
1548
  @Override
1549
  public int getTypeOfItems() {
1550
    return DataTypes.INVALID;
1551
  }
1552

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

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

    
1563
  @Override
1564
  public String getClassNameOfItems() {
1565
    return null;
1566
  }
1567

    
1568
  @Override
1569
  public DynStruct getDynClassOfItems() {
1570
    return null;
1571
  }
1572

    
1573
  @Override
1574
  public DynField setRelationType(int relationType) {
1575
    this.relationType = relationType;
1576
    return this;
1577
  }
1578

    
1579
  @Override
1580
  public int getRelationType() {
1581
    return this.relationType;
1582
  }
1583

    
1584
  @Override
1585
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1586
    this.availableValuesMethod = availableValuesMethod;
1587
    return this;
1588
  }
1589

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

    
1606
  @Override
1607
  public DynMethod getAvailableValuesMethod() {
1608
    return this.availableValuesMethod;
1609
  }
1610

    
1611
  @Override
1612
  public boolean isAvailableValuesCalculated() {
1613
    return this.availableValuesMethod != null;
1614
  }
1615

    
1616
  @Override
1617
  public DynMethod getCalculateMethod() {
1618
    return this.calculateMethod;
1619
  }
1620

    
1621
  @Override
1622
  public DynField setCalculateMethod(DynMethod method) {
1623
    this.calculateMethod = method;
1624
    return this;
1625
  }
1626

    
1627
  @Override
1628
  public boolean isCalculated() {
1629
    return this.calculateMethod != null;
1630
  }
1631

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

    
1641
  @Override
1642
  public DynField setValidateElements(boolean validate) {
1643
    return this;
1644
  }
1645

    
1646
  @Override
1647
  public boolean getValidateElements() {
1648
    return false;
1649
  }
1650

    
1651
  @Override
1652
  public boolean hasLabel() {
1653
    return StringUtils.isNotBlank(this.label);
1654
  }
1655

    
1656
  @Override
1657
  public boolean hasShortLabel() {
1658
    return StringUtils.isNotBlank(this.shortLabel);
1659
  }
1660

    
1661
  @Override
1662
  public boolean hasDescription() {
1663
    return StringUtils.isNotBlank(this.description);
1664
  }
1665

    
1666
  @Override
1667
  public FeatureAttributeDescriptor getValue() {
1668
    return this;
1669
  }
1670

    
1671
  @Override
1672
  public int getDisplaySize() {
1673
    return this.displaySize;
1674
  }
1675

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

    
1688
  private class ConstantValueEvaluator extends AbstractEvaluator {
1689

    
1690
    @Override
1691
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1692
      return defaultValue;
1693
    }
1694

    
1695
    @Override
1696
    public String getName() {
1697
      return "Constant attribute " + name;
1698
    }
1699
  }
1700

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

    
1715
  @Override
1716
  public boolean isComputed() {
1717
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1718
  }
1719

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

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

    
1739
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1740
    this.interval = interval;
1741
    return this;
1742
  }
1743

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

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

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

    
1774
  @Override
1775
  public void recentUsed() {
1776
    DefaultFeatureType.RECENTS_USEDS.add(this);
1777
  }
1778

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

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

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

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

    
2084
    @Override
2085
    public JsonObjectBuilder toJsonBuilder() {
2086
        JsonObjectBuilder builder = Json.createObjectBuilder();
2087

    
2088
        JsonUtils.builder_add(builder, "name", this.name);
2089
        JsonUtils.builder_add(builder, "description", this.description);
2090
        JsonUtils.builder_add(builder, "label", this.label);
2091
        JsonUtils.builder_add(builder, "shortLabel", this.shortLabel);
2092
        JsonUtils.builder_add(builder, "order", this.order);
2093
        JsonUtils.builder_add(builder, "groupName", this.groupName);
2094
        JsonUtils.builder_add(builder, "dataType", this.dataType.getName());
2095
        JsonUtils.builder_add(builder, "size", this.size);
2096
        JsonUtils.builder_add(builder, "precision", this.precision);
2097
        JsonUtils.builder_add(builder, "scale", this.scale);
2098
        JsonUtils.builder_add(builder, "roundMode", this.roundMode);
2099

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

    
2111
        JsonUtils.builder_add(builder, "geometryType",this.getGeomType());
2112
        JsonUtils.builder_add(builder, "srs", this.getSRS());
2113

    
2114
        JsonUtils.builder_add(builder, "relationType", this.relationType);
2115
        JsonUtils.builder_add(builder, "displaySize", this.displaySize);
2116
        JsonUtils.builder_add(builder, "locale", this.getLocale());
2117
        JsonUtils.builder_add(builder, "expression", this.getFeatureAttributeEmulator());
2118
        if( this.isForeingKey() ) {
2119
            JsonUtils.builder_add(builder, "fk", this.isForeingKey());
2120
            JsonUtils.builder_add(builder, "fk_table", this.getForeingKey().getTableName());
2121
            JsonUtils.builder_add(builder, "fk_code", this.getForeingKey().getCodeName());
2122
            JsonUtils.builder_add(builder, "fk_label", this.getForeingKey().getLabelFormula());
2123
            JsonUtils.builder_add(builder, "fk.closedlist", this.getForeingKey().isClosedList());
2124
        }
2125
        JsonUtils.builder_add(builder, "availableValuesExpression", this.availableValuesExpression);
2126
        JsonUtils.builder_add(builder, "defaultValue", Objects.toString(this.defaultValue,""));
2127
        JsonUtils.builder_add(builder, "dataProfile", this.getDataProfileName());
2128
        JsonUtils.builder_add(builder, "tags", tags);
2129
        JsonUtils.builder_add(builder, "availableValues", availableValues);
2130
        if( this.additionalInfo!=null && !additionalInfo.isEmpty() ) {
2131
            JsonArrayBuilder ab = Json.createArrayBuilder();
2132
            for (Map.Entry<String,String> info : additionalInfo.entrySet()) {
2133
                JsonObjectBuilder x = Json.createObjectBuilder();
2134
                JsonUtils.builder_add(x, "key", info.getKey());
2135
                JsonUtils.builder_add(x, "value", info.getValue());
2136
                ab.add(x);
2137
            }
2138
            JsonUtils.builder_add(builder, "additionalInfo", ab);
2139
        }
2140
        return builder;
2141
    }
2142
    
2143
}