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

History | View | Annotate | Download (67 KB)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
499
  @Override
500
  public CoercionContext getCoercionContext() {
501
    if (this.coerceContext == null) {
502
      if (this.getDataType().isNumeric()) {
503
        this.coerceContext = DataTypeUtils.coerceContextDecimal(
504
                this.getLocale(),
505
                this.getPrecision(),
506
                this.getScale(),
507
                this.getRoundMode()
508
        );
509
      } else {
510
        this.coerceContext = DataTypeUtils.coerceContextLocale(
511
                this.getLocale()
512
        );
513
      }
514
    }
515
    return this.coerceContext;
516
  }
517

    
518
  @Override
519
  public int getRoundMode() {
520
    return this.roundMode;
521
  }
522

    
523
  @Override
524
  public IProjection getSRS() {
525
    return this.SRS;
526
  }
527

    
528
  @Override
529
  public Interval getInterval() {
530
    return this.interval;
531
  }
532

    
533
  public IProjection getSRS(WeakReference storeRef) {
534
    if (this.SRS == null) {
535
      FeatureStore store = (FeatureStore) storeRef.get();
536
      this.SRS = (IProjection) store.getDynValue(DataStore.METADATA_CRS);
537
    }
538
    return this.SRS;
539
  }
540

    
541
  @Override
542
  public int getSize() {
543
    return this.size;
544
  }
545

    
546
  @Override
547
  public boolean isPrimaryKey() {
548
    return this.primaryKey;
549
  }
550

    
551
  @Override
552
  public boolean isReadOnly() {
553
    if (this.readOnly) {
554
      return true;
555
    }
556
    return this.isComputed();
557
  }
558

    
559
  @Override
560
  public String getAdditionalInfo(String infoName) {
561
    if (this.additionalInfo == null) {
562
      return null;
563
    }
564
    return this.additionalInfo.get(infoName);
565
  }
566

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

    
572
  @Override
573
  public boolean equals(Object obj) {
574
    if (this == obj) {
575
      return true;
576
    }
577
    if (!(obj instanceof DefaultFeatureAttributeDescriptor)) {
578
      return false;
579
    }
580
    DefaultFeatureAttributeDescriptor other
581
            = (DefaultFeatureAttributeDescriptor) obj;
582

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

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

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

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

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

    
603
    if (!Objects.equals(this.defaultValue, other.defaultValue)) {
604
      return false;
605
    }
606

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

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

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

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

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

    
627
    if (this.minimumOccurrences != other.minimumOccurrences) {
628
      return false;
629
    }
630

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

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

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

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

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

    
651
    if (!Objects.equals(this.dateFormat, other.dateFormat)) {
652
      return false;
653
    }
654

    
655
    if (!Objects.equals(this.objectClass, other.objectClass)) {
656
      return false;
657
    }
658

    
659
    if (!Objects.equals(this.dataProfile, other.dataProfile)) {
660
      return false;
661
    }
662

    
663
    return true;
664
  }
665

    
666
  @Override
667
  public void loadFromState(PersistentState state)
668
          throws PersistenceException {
669
    allowNull = state.getBoolean("allowNull");
670
    dataType = ToolsLocator.getDataTypesManager().get(state.getInt("dataType"));
671
    dataProfile = state.getString("dataProfile");
672

    
673
//        FIXME: dateFormat;
674
    try {
675
      defaultValue = dataType.coerce(state.get("defaultValue"));
676
    } catch (CoercionException ex) {
677
    }
678

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

    
725
    Map<String, Object> values = state.getMap("availableValues");
726
    if (values == null || values.isEmpty()) {
727
      this.availableValues = null;
728
    } else {
729
      this.availableValues = new DynObjectValueItem[values.size()];
730
      int n = 0;
731
      for (Entry<String, Object> entry : values.entrySet()) {
732
        this.availableValues[n++] = new DynObjectValueItem(entry.getValue(), entry.getKey());
733
      }
734
    }
735

    
736
    description = state.getString("description");
737
    minValue = state.get("minValue");
738
    maxValue = state.get("maxValue");
739
    label = state.getString("label");
740
    order = state.getInt("order");
741
    hidden = state.getBoolean("hidden");
742
    groupName = state.getString("groupName");
743
    relationType = state.getInt("relationType", RELATION_TYPE_NONE);
744

    
745
    foreingKey = (DefaultForeingKey) state.get("foreingKey");
746
    if (foreingKey != null) {
747
      this.foreingKey.setDescriptor(this);
748
    }
749
    tags = (Tags) state.get("tags");
750
    if (tags == null) {
751
      this.tags = new DefaultTags();
752
    }
753
    displaySize = state.getInt("displaySize",0);
754
    availableValuesExpression = (Expression) state.get("availableValuesExpression");
755
    avoidCachingAvailableValues = state.getBoolean("avoidCachingAvailableValues",false);
756
    availableValuesCache = null;
757
    
758
  }
759

    
760
  @Override
761
  public void saveToState(PersistentState state) throws PersistenceException {
762
    Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
763
    
764
    state.set("allowNull", allowNull);
765
    state.set("dataType", dataType.getType());
766
    state.set("dataProfile", dataProfile);
767

    
768
//        FIXME: dateFormat;
769
    state.set("defaultValue", Objects.toString(defaultValue, null));
770

    
771
    state.set("index", index);
772
    state.set("maximumOccurrences", maximumOccurrences);
773
    state.set("minimumOccurrences", minimumOccurrences);
774
    state.set("size", size);
775
    state.set("name", name);
776
    state.set("objectClass", objectClass == null ? null : objectClass.getName());
777
    state.set("precision", precision);
778
    state.set("scale", scale);
779
    state.set("roundMode", roundMode);    
780
    if( this.locale == null ) {
781
      state.setNull("locale");
782
    } else {
783
      state.set("locale", this.locale.toLanguageTag()); //toString.coerce(this.locale));
784
    }
785
    state.set("evaluator", evaluator);
786

    
787
    state.set("primaryKey", primaryKey);
788
    state.set("readOnly", readOnly);
789
    state.set("SRS", SRS);
790
    GeometryType theGeomType = this.getGeomType();
791
    if (theGeomType == null) {
792
      state.set("geometryType", Geometry.TYPES.UNKNOWN);
793
      state.set("geometrySubType", Geometry.SUBTYPES.UNKNOWN);
794
    } else {
795
      state.set("geometryType", theGeomType.getType());
796
      state.set("geometrySubType", theGeomType.getSubType());
797
    }
798

    
799
//      FIXME: additionalInfo
800
    state.set("isAutomatic", isAutomatic);
801
    state.set("isTime", isTime);
802
    if (this.interval == null) {
803
      state.setNull("interval_start");
804
      state.setNull("interval_end");
805
    } else {
806
      state.set("interval_start", ((RelativeInterval) interval).getStart().toMillis());
807
      state.set("interval_end", ((RelativeInterval) interval).getEnd().toMillis());
808
    }
809
    state.set("SRS", SRS);
810

    
811
//      FIXME: featureAttributeGetter
812
    if (featureAttributeEmulator instanceof Persistent) {
813
      state.set("featureAttributeEmulator", featureAttributeEmulator);
814
    } else {
815
      state.setNull("featureAttributeEmulator");
816
    }
817

    
818
    state.set("indexed", indexed);
819
    state.set("isIndexAscending", isIndexAscending);
820
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
821

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

    
840
    state.set("foreingKey", this.foreingKey);
841
    state.set("tags", this.tags);
842

    
843
    state.set("displaySize", displaySize);
844
    state.set("availableValuesExpression", availableValuesExpression);
845
    state.set("avoidCachingAvailableValues", avoidCachingAvailableValues);    
846
  }
847

    
848
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
849

    
850
  public static void registerPersistenceDefinition() {
851
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
852

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

    
906
      definition.addDynFieldObject("foreingKey")
907
              .setClassOfValue(DefaultForeingKey.class);
908

    
909
      definition.addDynFieldObject("tags")
910
              .setClassOfValue(Tags.class);
911

    
912
      definition.addDynFieldInt("displaySize").setMandatory(false);
913
      definition.addDynFieldObject("availableValuesExpression")
914
              .setClassOfValue(Expression.class)
915
              .setMandatory(false);
916
    }
917
  }
918

    
919
  /*
920
     * Start of DynField interface Implementation
921
     *
922
   */
923
  @Override
924
  public Tags getTags() {
925
    return tags;
926
  }
927

    
928
  @Override
929
  public boolean hasConstantAvailableValues() {
930
    return this.availableValues != null;
931
  }
932

    
933
  @Override
934
  public boolean isAvoidCachingAvailableValues() {
935
    return this.avoidCachingAvailableValues;
936
  }
937
  
938
  public boolean hasAvailableValues() {
939
      return getAvailableValues()!=null;
940
  }
941
  
942
  @Override
943
  public DynObjectValueItem[] getAvailableValues() {
944
    DynObjectValueItem[] values = this.availableValues;
945
    
946
    if (values != null) {
947
        return values;
948
    }
949
    values = this.availableValuesCache;
950
    if (values != null) {
951
        return values;
952
    }
953
    if (this.isForeingKey() && this.foreingKey.isClosedList()) {
954
      values = this.foreingKey.getAvailableValues(null);
955

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

    
1100
  private DynObjectValueItem[] getAvailableValuesFromExpression() {
1101
      if( this.availableValuesExpression == null || this.availableValuesExpression.isEmpty() ) {
1102
          return null;
1103
      }
1104
      try {
1105
        Object value = this.availableValuesExpression.execute(null);
1106
        if( value instanceof DynObjectValueItem[] ) {
1107
            return (DynObjectValueItem[]) value;
1108
        }
1109
        if( value instanceof List ) {
1110
            return this.getAvailableValuesFrom(new GetItemWithSize() {
1111
                @Override
1112
                public Object get(int i) {
1113
                    return ((List)value).get(i);
1114
                }
1115

    
1116
                @Override
1117
                public int size() {
1118
                    return ((List)value).size();
1119
                }
1120
            });
1121
        }
1122
      } catch(Throwable th) {
1123
          LOGGER.warn("Can't get available values from expression", th);
1124
      }
1125
      return null;
1126
  }
1127

    
1128
  @Override
1129
  public Expression getAvailableValuesExpression() {
1130
      return this.availableValuesExpression;
1131
  }
1132
  
1133
  @Override
1134
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1135
        if (StringUtils.isBlank(expression)) {
1136
            this.availableValuesExpression = null;
1137
            return this;
1138
        }
1139
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1140
        return this;
1141
    }
1142

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

    
1174
  @Override
1175
  public String getDescription() {
1176
    if (this.description == null) {
1177
      return getName();
1178
    }
1179
    return this.description;
1180
  }
1181

    
1182
  @Override
1183
  public Object getMaxValue() {
1184
    return this.maxValue;
1185
  }
1186

    
1187
  @Override
1188
  public Object getMinValue() {
1189
    return this.minValue;
1190
  }
1191

    
1192
  @Override
1193
  public int getTheTypeOfAvailableValues() {
1194
    return 1;
1195
  }
1196

    
1197
  @Override
1198
  public int getType() {
1199
    if (featureAttributeGetter != null) {
1200
      return featureAttributeGetter.getDataType().getType();
1201
    }
1202
    return getDataType().getType();
1203
  }
1204

    
1205
  @Override
1206
  public boolean isMandatory() {
1207
    return !allowNull() || isPrimaryKey();
1208
  }
1209

    
1210
  @Override
1211
  public boolean isPersistent() {
1212
    return false;
1213
  }
1214

    
1215
  @Override
1216
  public DynField setAvailableValues(DynObjectValueItem[] values) {
1217
    if (ArrayUtils.isEmpty(values)) {
1218
      this.availableValues = null;
1219
    } else {
1220
      this.availableValues = values;
1221
    }
1222
    return this;
1223
  }
1224

    
1225
  @Override
1226
  public DynField setDescription(String description) {
1227
    this.description = description;
1228
    return this;
1229
  }
1230

    
1231
  @Override
1232
  public DynField setMandatory(boolean mandatory) {
1233
    throw new UnsupportedOperationException();
1234
  }
1235

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

    
1246
  @Override
1247
  public DynField setMinValue(Object minValue) {
1248
    try {
1249
      this.maxValue = this.coerce(minValue);
1250
    } catch (CoercionException e) {
1251
      throw new IllegalArgumentException(e);
1252
    }
1253
    return this;
1254
  }
1255

    
1256
  @Override
1257
  public DynField setPersistent(boolean persistent) {
1258
    throw new UnsupportedOperationException();
1259
  }
1260

    
1261
  @Override
1262
  public DynField setTheTypeOfAvailableValues(int type) {
1263
    throw new UnsupportedOperationException();
1264
  }
1265

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

    
1271
  @Override
1272
  @Deprecated
1273
  public DynField setDefaultDynValue(Object defaultValue) {
1274
    return this.setDefaultFieldValue(defaultValue);
1275
  }
1276

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

    
1283
  @Override
1284
  public Class getClassOfValue() {
1285
    return null;
1286
  }
1287

    
1288
  @Override
1289
  public DynField getElementsType() {
1290
    return null;
1291
  }
1292

    
1293
  @Override
1294
  public DynField setClassOfValue(Class theClass)
1295
          throws DynFieldIsNotAContainerException {
1296
    throw new UnsupportedOperationException();
1297
  }
1298

    
1299
  @Override
1300
  public DynField setElementsType(DynStruct type)
1301
          throws DynFieldIsNotAContainerException {
1302
    throw new UnsupportedOperationException();
1303
  }
1304

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

    
1311
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1312
    this.dataProfile = dataProfile;
1313
    return this;
1314
  }
1315

    
1316
  @Override
1317
  public String getDataProfileName() {
1318
    return dataProfile;
1319
  }
1320

    
1321
  @Override
1322
  public DataProfile getDataProfile() {
1323
    if (StringUtils.isBlank(dataProfile)) {
1324
      return null;
1325
    }
1326
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1327
    return profile;
1328
  }
1329

    
1330
  @Override
1331
  public void validate(Object value) throws DynFieldValidateException {
1332

    
1333
    if (value == null && !this.allowNull()) {
1334
      throw new DynFieldValidateException(value, this, null);
1335
    }
1336

    
1337
    try {
1338
      this.dataType.coerce(value);
1339
    } catch (CoercionException e) {
1340
      throw new DynFieldValidateException(value, this, e);
1341
    }
1342

    
1343
    /*
1344
         * Other checks will be needed
1345
     */
1346
  }
1347

    
1348
  @Override
1349
  public String getSubtype() {
1350
    if (featureAttributeGetter != null) {
1351
      return featureAttributeGetter.getDataType().getSubtype();
1352
    }
1353
    return this.dataType.getSubtype();
1354
  }
1355

    
1356
  @Override
1357
  public Object coerce(Object value) throws CoercionException {
1358
    if (value == null) {
1359
      return value; // O debe devolver this.defaultValue
1360
    }
1361
    try {
1362
      return this.getDataType().coerce(value, this.getCoercionContext());
1363
    } catch (Exception ex) {
1364
      throw new RuntimeException(ex);
1365
    }
1366
  }
1367

    
1368
  @Override
1369
  public DynField setAvailableValues(List values) {
1370
    if (values == null || values.isEmpty()) {
1371
      this.availableValues = null;
1372
    } else {
1373
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1374
              new DynObjectValueItem[values.size()]
1375
      );
1376
    }
1377
    return this;
1378
  }
1379

    
1380
  @Override
1381
  public String getGroup() {
1382
    return this.groupName;
1383
  }
1384

    
1385
  @Override
1386
  public int getOder() {
1387
    return this.order;
1388
  }
1389

    
1390
  @Override
1391
  public String getLabel() {
1392
    if (this.label == null) {
1393
      return this.getName();
1394
    }
1395
    return this.label;
1396
  }
1397

    
1398
  @Override
1399
  public String getLocalizedLabel() {
1400
    if (StringUtils.isBlank(this.label)) {
1401
      return this.getName();
1402
    }
1403
    I18nManager i18n = ToolsLocator.getI18nManager();
1404
    return i18n.getTranslation(this.label);
1405
  }
1406

    
1407
  @Override
1408
  public DynField setLabel(String label) {
1409
    this.label = label;
1410
    return this;
1411
  }
1412

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

    
1419
  @Override
1420
  public String getShortLabel() {
1421
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1422
  }
1423

    
1424
  @Override
1425
  public String getLocalizedShortLabel() {
1426
    if (StringUtils.isBlank(shortLabel)) {
1427
      return this.getLocalizedLabel();
1428
    }
1429
    I18nManager i18n = ToolsLocator.getI18nManager();
1430
    return i18n.getTranslation(shortLabel);
1431
  }
1432

    
1433
  @Override
1434
  public DynField setGroup(String groupName) {
1435
    this.groupName = groupName;
1436
    return this;
1437
  }
1438

    
1439
  @Override
1440
  public DynField setOrder(int order) {
1441
    this.order = order;
1442
    return this;
1443
  }
1444

    
1445
  @Override
1446
  public DynField setHidden(boolean hidden) {
1447
    this.hidden = hidden;
1448
    return this;
1449
  }
1450

    
1451
  @Override
1452
  public boolean isHidden() {
1453
    return this.hidden;
1454
  }
1455

    
1456
  @Override
1457
  public DynField setReadOnly(boolean readOnly) {
1458
    this.readOnly = readOnly;
1459
    return this;
1460
  }
1461

    
1462
  @Override
1463
  public boolean isContainer() {
1464
    return false;
1465
  }
1466

    
1467
  @Override
1468
  public Class getClassOfItems() {
1469
    return null;
1470
  }
1471

    
1472
  @Override
1473
  public DynField setClassOfItems(Class theClass) {
1474
    throw new UnsupportedOperationException();
1475
  }
1476

    
1477
  @Override
1478
  public DynField setType(DataType type) {
1479
    throw new UnsupportedOperationException();
1480
  }
1481

    
1482
  @Override
1483
  public DynField setSubtype(String subtype) {
1484
    throw new UnsupportedOperationException();
1485
  }
1486

    
1487
  @Override
1488
  public boolean isTime() {
1489
    return isTime;
1490
  }
1491

    
1492
  @Override
1493
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1494
    return featureAttributeGetter;
1495
  }
1496

    
1497
  @Override
1498
  public void setFeatureAttributeGetter(
1499
          FeatureAttributeGetter featureAttributeTransform) {
1500
    this.featureAttributeGetter = featureAttributeTransform;
1501
  }
1502

    
1503
  @Override
1504
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1505
    return this.featureAttributeEmulator;
1506
  }
1507

    
1508
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1509
    this.featureAttributeEmulator = featureAttributeEmulator;
1510
    return this;
1511
  }
1512

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

    
1518
  @Override
1519
  public boolean isForeingKey() {
1520
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1521
  }
1522

    
1523
  @Override
1524
  public ForeingKey getForeingKey() {
1525
    return this.foreingKey;
1526
  }
1527

    
1528
  @Override
1529
  public boolean allowIndexDuplicateds() {
1530
    return this.allowIndexDuplicateds;
1531
  }
1532

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

    
1538
  @Override
1539
  public DynField setClassOfValue(DynStruct dynStrct) {
1540
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1541
  }
1542

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

    
1548
  @Override
1549
  public String getClassNameOfValue() {
1550
    return null;
1551
  }
1552

    
1553
  @Override
1554
  public DynStruct getDynClassOfValue() {
1555
    return null;
1556
  }
1557

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

    
1563
  @Override
1564
  public int getTypeOfItems() {
1565
    return DataTypes.INVALID;
1566
  }
1567

    
1568
  @Override
1569
  public DynField setClassOfItems(DynStruct dynStrct) {
1570
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1571
  }
1572

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

    
1578
  @Override
1579
  public String getClassNameOfItems() {
1580
    return null;
1581
  }
1582

    
1583
  @Override
1584
  public DynStruct getDynClassOfItems() {
1585
    return null;
1586
  }
1587

    
1588
  @Override
1589
  public DynField setRelationType(int relationType) {
1590
    this.relationType = relationType;
1591
    return this;
1592
  }
1593

    
1594
  @Override
1595
  public int getRelationType() {
1596
    return this.relationType;
1597
  }
1598

    
1599
  @Override
1600
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1601
    this.availableValuesMethod = availableValuesMethod;
1602
    return this;
1603
  }
1604

    
1605
  @Override
1606
  public DynObjectValueItem[] getAvailableValues(DynObject self) {
1607
    if (this.availableValuesMethod != null) {
1608
      DynObjectValueItem[] values;
1609
      try {
1610
        values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self, new Object[]{this});
1611
      } catch (DynMethodException ex) {
1612
        return this.availableValues;
1613
      }
1614
      if (values != null) {
1615
        return values;
1616
      }
1617
    }
1618
    return this.availableValues;
1619
  }
1620

    
1621
  @Override
1622
  public DynMethod getAvailableValuesMethod() {
1623
    return this.availableValuesMethod;
1624
  }
1625

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

    
1631
  @Override
1632
  public DynMethod getCalculateMethod() {
1633
    return this.calculateMethod;
1634
  }
1635

    
1636
  @Override
1637
  public DynField setCalculateMethod(DynMethod method) {
1638
    this.calculateMethod = method;
1639
    return this;
1640
  }
1641

    
1642
  @Override
1643
  public boolean isCalculated() {
1644
    return this.calculateMethod != null;
1645
  }
1646

    
1647
  @Override
1648
  public Object getCalculatedValue(DynObject self) {
1649
    try {
1650
      return this.calculateMethod.invoke(self, new Object[]{this});
1651
    } catch (DynMethodException ex) {
1652
      throw new RuntimeException(ex);
1653
    }
1654
  }
1655

    
1656
  @Override
1657
  public DynField setValidateElements(boolean validate) {
1658
    return this;
1659
  }
1660

    
1661
  @Override
1662
  public boolean getValidateElements() {
1663
    return false;
1664
  }
1665

    
1666
  @Override
1667
  public boolean hasLabel() {
1668
    return StringUtils.isNotBlank(this.label);
1669
  }
1670

    
1671
  @Override
1672
  public boolean hasShortLabel() {
1673
    return StringUtils.isNotBlank(this.shortLabel);
1674
  }
1675

    
1676
  @Override
1677
  public boolean hasDescription() {
1678
    return StringUtils.isNotBlank(this.description);
1679
  }
1680

    
1681
  @Override
1682
  public FeatureAttributeDescriptor getValue() {
1683
    return this;
1684
  }
1685

    
1686
  @Override
1687
  public int getDisplaySize() {
1688
    return this.displaySize;
1689
  }
1690

    
1691
    @Override
1692
    public boolean isInAvailableValues(Object valueToCheck) {
1693
        if (this.getAvailableValues()!=null) {
1694
            for (DynObjectValueItem availableValue : this.getAvailableValues()) {
1695
                if (Objects.equals(valueToCheck, availableValue.getValue())) {
1696
                    return true;
1697
                }
1698
            }
1699
        }
1700
        return false;
1701
    }
1702

    
1703
  private class ConstantValueEvaluator extends AbstractEvaluator {
1704

    
1705
    @Override
1706
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1707
      return defaultValue;
1708
    }
1709

    
1710
    @Override
1711
    public String getName() {
1712
      return "Constant attribute " + name;
1713
    }
1714
  }
1715

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

    
1730
  @Override
1731
  public boolean isComputed() {
1732
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1733
  }
1734

    
1735
  @Override
1736
  public FeatureStore getStore() {
1737
    FeatureType ftype = this.getFeatureType();
1738
    if (ftype == null) {
1739
      return null;
1740
    }
1741
    return ftype.getStore();
1742
  }
1743

    
1744
  @Override
1745
  public FeatureType getFeatureType() {
1746
    if (this.typeRef == null) {
1747
      return null;
1748
    }
1749
    FeatureType ftype = (FeatureType) this.typeRef.get();
1750
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1751
    return ftype;
1752
  }
1753

    
1754
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1755
    this.interval = interval;
1756
    return this;
1757
  }
1758

    
1759
  public void fixAll() {
1760
    if (!this.getDataType().supportSize()) {
1761
      this.size = 0;
1762
    }
1763
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1764
    this.precision = ps.getPrecision();
1765
    this.scale = ps.getScale();
1766

    
1767
    switch (this.getType()) {
1768
      case DataTypes.INSTANT:
1769
      case DataTypes.INTERVAL:
1770
      case DataTypes.DATE:
1771
      case DataTypes.TIME:
1772
      case DataTypes.TIMESTAMP:
1773
        if (this.getInterval() != null) {
1774
          this.isTime = true;
1775
        }
1776
        break;
1777
    }
1778
  }
1779

    
1780
  @Override
1781
  public String[] getRequiredFieldNames() {
1782
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1783
    if (emulator == null) {
1784
      return null;
1785
    }
1786
    return emulator.getRequiredFieldNames();
1787
  }
1788

    
1789
  @Override
1790
  public void recentUsed() {
1791
    DefaultFeatureType.RECENTS_USEDS.add(this);
1792
  }
1793

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

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

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

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

    
2095
    @Override
2096
    public JsonObjectBuilder toJsonBuilder() {
2097
        JsonObjectBuilder builder = Json.createObjectBuilder();
2098
        builder.add_class(this);
2099
        builder.add("name", this.name);
2100
        builder.add("description", this.description);
2101
        builder.add("label", this.label);
2102
        builder.add("shortLabel", this.shortLabel);
2103
        builder.add("order", this.order);
2104
        builder.add("groupName", this.groupName);
2105
        builder.add("dataType", this.dataType);
2106
        builder.add("size", this.size);
2107
        builder.add("precision", this.precision);
2108
        builder.add("scale", this.scale);
2109
        builder.add("roundMode", this.roundMode);
2110

    
2111
        builder.add("allowNull", this.allowNull);
2112
        builder.add("primaryKey", this.primaryKey);
2113
        builder.add("readOnly", this.readOnly);
2114
        builder.add("isAutomatic", this.isAutomatic);
2115
        builder.add("isTime", this.isTime);
2116
        builder.add("indexed", this.indexed);
2117
        builder.add("isIndexAscending", this.isIndexAscending);
2118
        builder.add("allowIndexDuplicateds", this.allowIndexDuplicateds);
2119
        builder.add("hidden", this.hidden);
2120
        builder.add("avoidCachingAvailableValues", this.avoidCachingAvailableValues);
2121

    
2122
        builder.add("geometryType",this.getGeomType());
2123
        builder.add("srs", this.getSRS());
2124

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

    
2168
        this.relationType = json.getInt("relationType");
2169
        this.displaySize = json.getInt("displaySize");
2170

    
2171
        this.dataType = (DataType) Json.toObject(json,"dataType");
2172
        this.geomType = (GeometryType) Json.toObject(json, "geometryType");
2173
        this.SRS = (IProjection) Json.toObject(json, "srs");
2174
        this.locale = (Locale) Json.toObject(json, "locale");
2175
        this.featureAttributeEmulator = (FeatureAttributeEmulator) Json.toObject(json,"expression");
2176

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

    
2201
        @Override
2202
        public Class getObjectClass() {
2203
            return DefaultFeatureAttributeDescriptor.class;
2204
        }
2205

    
2206
        @Override
2207
        public Object toObject(JsonObject json) {
2208
            DefaultFeatureAttributeDescriptor o = new DefaultFeatureAttributeDescriptor();
2209
            o.fromJson(json);
2210
            return o;
2211
        }
2212

    
2213
        @Override
2214
        public JsonObjectBuilder toJsonBuilder(Object value) {
2215
            return ((SupportToJson)value).toJsonBuilder();
2216
        }
2217
        
2218
    }
2219

    
2220
    public static void selfRegister() {
2221
        Json.registerSerializer(new TheJsonSerializer());
2222
    }
2223

    
2224
}