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

History | View | Annotate | Download (64.1 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.StringUtils;
44
import org.apache.commons.lang3.tuple.Pair;
45
import org.cresques.cts.IProjection;
46
import org.gvsig.expressionevaluator.Expression;
47
import org.gvsig.expressionevaluator.ExpressionUtils;
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.timesupport.Interval;
66
import org.gvsig.timesupport.RelativeInterval;
67
import org.gvsig.timesupport.TimeSupportLocator;
68
import org.gvsig.tools.ToolsLocator;
69
import org.gvsig.tools.dataTypes.Coercion;
70
import org.gvsig.tools.dataTypes.CoercionException;
71
import org.gvsig.tools.dataTypes.DataType;
72
import org.gvsig.tools.dataTypes.DataTypeUtils;
73
import org.gvsig.tools.dynobject.DynField;
74
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
75
import org.gvsig.tools.dynobject.DynField_v2;
76
import org.gvsig.tools.dynobject.DynMethod;
77
import org.gvsig.tools.dynobject.DynObject;
78
import org.gvsig.tools.dynobject.DynObjectValueItem;
79
import org.gvsig.tools.dynobject.DynStruct;
80
import org.gvsig.tools.dynobject.Tags;
81
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
82
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
83
import org.gvsig.tools.dynobject.exception.DynMethodException;
84
import org.gvsig.tools.dynobject.impl.DefaultTags;
85
import org.gvsig.tools.evaluator.AbstractEvaluator;
86
import org.gvsig.tools.evaluator.Evaluator;
87
import org.gvsig.tools.evaluator.EvaluatorData;
88
import org.gvsig.tools.evaluator.EvaluatorException;
89
import org.gvsig.tools.i18n.I18nManager;
90
import org.gvsig.tools.persistence.PersistenceManager;
91
import org.gvsig.tools.persistence.Persistent;
92
import org.gvsig.tools.persistence.PersistentState;
93
import org.gvsig.tools.persistence.exception.PersistenceException;
94
import org.slf4j.Logger;
95
import org.slf4j.LoggerFactory;
96
import org.gvsig.tools.dataTypes.CoercionContext;
97
import org.gvsig.tools.dataTypes.DataType.NumberPrecisionAndScale;
98
import org.gvsig.tools.util.GetItemWithSize;
99
import org.gvsig.tools.util.LabeledValue;
100

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
649
    return true;
650
  }
651

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

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

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

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

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

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

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

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

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

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

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

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

    
808
    state.set("indexed", indexed);
809
    state.set("isIndexAscending", isIndexAscending);
810
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
811

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

    
830
    state.set("foreingKey", this.foreingKey);
831
    state.set("tags", this.tags);
832

    
833
    state.set("displaySize", displaySize);
834
    state.set("availableValuesExpression", availableValuesExpression);
835
    state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);    
836
  }
837

    
838
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
839

    
840
  public static void registerPersistenceDefinition() {
841
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
842

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

    
896
      definition.addDynFieldObject("foreingKey")
897
              .setClassOfValue(DefaultForeingKey.class);
898

    
899
      definition.addDynFieldObject("tags")
900
              .setClassOfValue(Tags.class);
901

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1675
  private class ConstantValueEvaluator extends AbstractEvaluator {
1676

    
1677
    @Override
1678
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1679
      return defaultValue;
1680
    }
1681

    
1682
    @Override
1683
    public String getName() {
1684
      return "Constant attribute " + name;
1685
    }
1686
  }
1687

    
1688
  public void setConstantValue(boolean isConstantValue) {
1689
    if (isConstantValue) {
1690
      /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1691
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1692
             * el evaluador el que se encarga de proporcionar su valor.
1693
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1694
             * por defecto para ese attributo.
1695
       */
1696
      this.evaluator = new ConstantValueEvaluator();
1697
    } else {
1698
      this.evaluator = null;
1699
    }
1700
  }
1701

    
1702
  @Override
1703
  public boolean isComputed() {
1704
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1705
  }
1706

    
1707
  @Override
1708
  public FeatureStore getStore() {
1709
    FeatureType ftype = this.getFeatureType();
1710
    if (ftype == null) {
1711
      return null;
1712
    }
1713
    return ftype.getStore();
1714
  }
1715

    
1716
  @Override
1717
  public FeatureType getFeatureType() {
1718
    if (this.typeRef == null) {
1719
      return null;
1720
    }
1721
    FeatureType ftype = (FeatureType) this.typeRef.get();
1722
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1723
    return ftype;
1724
  }
1725

    
1726
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1727
    this.interval = interval;
1728
    return this;
1729
  }
1730

    
1731
  public void fixAll() {
1732
    if (!this.getDataType().supportSize()) {
1733
      this.size = 0;
1734
    }
1735
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1736
    this.precision = ps.getPrecision();
1737
    this.scale = ps.getScale();
1738

    
1739
    switch (this.getType()) {
1740
      case DataTypes.INSTANT:
1741
      case DataTypes.INTERVAL:
1742
      case DataTypes.DATE:
1743
      case DataTypes.TIME:
1744
      case DataTypes.TIMESTAMP:
1745
        if (this.getInterval() != null) {
1746
          this.isTime = true;
1747
        }
1748
        break;
1749
    }
1750
  }
1751

    
1752
  @Override
1753
  public String[] getRequiredFieldNames() {
1754
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1755
    if (emulator == null) {
1756
      return null;
1757
    }
1758
    return emulator.getRequiredFieldNames();
1759
  }
1760

    
1761
  @Override
1762
  public void recentUsed() {
1763
    DefaultFeatureType.RECENTS_USEDS.add(this);
1764
  }
1765

    
1766
  @Override
1767
  public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1768
    if (other == null) {
1769
      throw new NullPointerException();
1770
    }
1771
    DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1772
    if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1773
      return false;
1774
    }
1775
    if (old.isComputed() && old.isComputed() == this.isComputed()) {
1776
      return true;
1777
    }
1778
    if (this.dataType != old.dataType) {
1779
      return false;
1780
    }
1781
    if (this.size != old.size) {
1782
      return false;
1783
    }
1784
    if (this.precision != old.precision) {
1785
      return false;
1786
    }
1787
//        if( this.primaryKey != old.primaryKey ) {
1788
//            return false;
1789
//        }
1790
    if (this.geomType != old.geomType) {
1791
      return false;
1792
    }
1793
    if (this.SRS != old.SRS) {
1794
      return false;
1795
    }
1796
    if (this.isAutomatic != old.isAutomatic) {
1797
      return false;
1798
    }
1799
    return true;
1800
  }
1801
  
1802
  private class PropertiesBuilder {
1803

    
1804
        private String name;
1805
        private DataType type;
1806
        private Map<String,String> sets;
1807
        private String sep;
1808
      
1809
      public PropertiesBuilder() {
1810
          this.sets = new LinkedHashMap<>();
1811
      }
1812
      
1813
      public void separator(String sep) {
1814
          this.sep = sep;
1815
      }
1816
      
1817
      public void name(String name) {
1818
        this.name = name;
1819
      }
1820
      
1821
      public void type(DataType type) {
1822
          this.type = type;
1823
      }
1824
      
1825
      public void set(String name, ForeingKey fk) {
1826
          if( fk == null ) {
1827
              return;
1828
          }
1829
          if( !fk.isForeingKey() ) {
1830
              return;
1831
          }
1832
          this.set(name, fk.isForeingKey());
1833
          this.set(name+"_code", fk.getCodeName());
1834
          this.set(name+"_label", fk.getLabelFormula());
1835
          this.set(name+"_closedlist", fk.isClosedList());
1836
          this.set(name+"_table", fk.getTableName());
1837
      }
1838

    
1839
      public void set(String name, FeatureAttributeEmulator value) {
1840
          if( value == null ) {
1841
              return;
1842
          }
1843
          if( value instanceof FeatureAttributeEmulatorExpression ) {
1844
            this.set(name, ((FeatureAttributeEmulatorExpression)value).getExpression().getPhrase());
1845
          }
1846
      }
1847
      
1848
      public void set(String name, IProjection value) {
1849
          if( value == null ) {
1850
              return;
1851
          }
1852
          this.set(name, value.getAbrev());
1853
      }
1854
      
1855
      public void set(String name, GeometryType value) {
1856
          if( value == null ) {
1857
              return;
1858
          }
1859
          this.set(name, value.getFullName().replace(":", "@"));
1860
      }
1861
      
1862
      public void set(String name, Object value) {
1863
          if( value == null ) {
1864
              return;
1865
          }
1866
          String s = Objects.toString(value, "");
1867
          if( StringUtils.isBlank(s) ) {
1868
              return;
1869
          }
1870
          this.sets.put(name, s);
1871
      }
1872
      
1873
      public void set(String name, Object value, Object skipValue) {
1874
          if( value == null || value == skipValue) {
1875
              return;
1876
          }
1877
          String s = Objects.toString(value, "");
1878
          if( StringUtils.isBlank(s) ) {
1879
              return;
1880
          }
1881
          this.sets.put(name, s);
1882
      }
1883
      
1884
      @Override
1885
      public String toString() {        
1886
        StringBuilder builder = new StringBuilder();
1887
        builder.append(this.name);
1888
        builder.append(sep);        
1889
        builder.append(this.type.getName());
1890
        for (String key : this.sets.keySet()) {
1891
            builder.append(sep);        
1892
            builder.append("set");
1893
            builder.append(sep);        
1894
            builder.append(key);        
1895
            builder.append("=");        
1896
            builder.append(this.sets.get(key));                    
1897
        }
1898
        return builder.toString();
1899
      }
1900
  }
1901

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

    
2071
    @Override
2072
    public JsonObjectBuilder toJsonBuilder() {
2073
        JsonObjectBuilder builder = Json.createObjectBuilder();
2074

    
2075
        JsonUtils.builder_add(builder, "name", this.name);
2076
        JsonUtils.builder_add(builder, "description", this.description);
2077
        JsonUtils.builder_add(builder, "label", this.label);
2078
        JsonUtils.builder_add(builder, "shortLabel", this.shortLabel);
2079
        JsonUtils.builder_add(builder, "order", this.order);
2080
        JsonUtils.builder_add(builder, "groupName", this.groupName);
2081
        JsonUtils.builder_add(builder, "dataType", this.dataType.getName());
2082
        JsonUtils.builder_add(builder, "size", this.size);
2083
        JsonUtils.builder_add(builder, "precision", this.precision);
2084
        JsonUtils.builder_add(builder, "scale", this.scale);
2085
        JsonUtils.builder_add(builder, "roundMode", this.roundMode);
2086

    
2087
        JsonUtils.builder_add(builder, "allowNull", this.allowNull);
2088
        JsonUtils.builder_add(builder, "primaryKey", this.primaryKey);
2089
        JsonUtils.builder_add(builder, "readOnly", this.readOnly);
2090
        JsonUtils.builder_add(builder, "isAutomatic", this.isAutomatic);
2091
        JsonUtils.builder_add(builder, "isTime", this.isTime);
2092
        JsonUtils.builder_add(builder, "indexed", this.indexed);
2093
        JsonUtils.builder_add(builder, "isIndexAscending", this.isIndexAscending);
2094
        JsonUtils.builder_add(builder, "allowIndexDuplicateds", this.allowIndexDuplicateds);
2095
        JsonUtils.builder_add(builder, "hidden", this.hidden);
2096
        JsonUtils.builder_add(builder, "avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2097

    
2098
        JsonUtils.builder_add(builder, "geometryType",this.getGeomType());
2099
        JsonUtils.builder_add(builder, "srs", this.getSRS());
2100

    
2101
        JsonUtils.builder_add(builder, "relationType", this.relationType);
2102
        JsonUtils.builder_add(builder, "displaySize", this.displaySize);
2103
        JsonUtils.builder_add(builder, "locale", this.getLocale());
2104
        JsonUtils.builder_add(builder, "expression", this.getFeatureAttributeEmulator());
2105
        if( this.isForeingKey() ) {
2106
            JsonUtils.builder_add(builder, "fk", this.isForeingKey());
2107
            JsonUtils.builder_add(builder, "fk_table", this.getForeingKey().getTableName());
2108
            JsonUtils.builder_add(builder, "fk_code", this.getForeingKey().getCodeName());
2109
            JsonUtils.builder_add(builder, "fk_label", this.getForeingKey().getLabelFormula());
2110
            JsonUtils.builder_add(builder, "fk.closedlist", this.getForeingKey().isClosedList());
2111
        }
2112
        JsonUtils.builder_add(builder, "availableValuesExpression", this.availableValuesExpression);
2113
        JsonUtils.builder_add(builder, "defaultValue", Objects.toString(this.defaultValue,""));
2114
        JsonUtils.builder_add(builder, "dataProfile", this.getDataProfileName());
2115
        JsonUtils.builder_add(builder, "tags", tags);
2116
        JsonUtils.builder_add(builder, "availableValues", availableValues);
2117
        if( this.additionalInfo!=null && !additionalInfo.isEmpty() ) {
2118
            JsonArrayBuilder ab = Json.createArrayBuilder();
2119
            for (Map.Entry<String,String> info : additionalInfo.entrySet()) {
2120
                JsonObjectBuilder x = Json.createObjectBuilder();
2121
                JsonUtils.builder_add(x, "key", info.getKey());
2122
                JsonUtils.builder_add(x, "value", info.getValue());
2123
                ab.add(x);
2124
            }
2125
            JsonUtils.builder_add(builder, "additionalInfo", ab);
2126
        }
2127
        return builder;
2128
    }
2129
    
2130
}