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

History | View | Annotate | Download (56.5 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.Iterator;
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.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.timesupport.Interval;
63
import org.gvsig.timesupport.RelativeInterval;
64
import org.gvsig.timesupport.TimeSupportLocator;
65
import org.gvsig.tools.ToolsLocator;
66
import org.gvsig.tools.dataTypes.Coercion;
67
import org.gvsig.tools.dataTypes.CoercionException;
68
import org.gvsig.tools.dataTypes.DataType;
69
import org.gvsig.tools.dataTypes.DataTypeUtils;
70
import org.gvsig.tools.dynobject.DynField;
71
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
72
import org.gvsig.tools.dynobject.DynField_v2;
73
import org.gvsig.tools.dynobject.DynMethod;
74
import org.gvsig.tools.dynobject.DynObject;
75
import org.gvsig.tools.dynobject.DynObjectValueItem;
76
import org.gvsig.tools.dynobject.DynStruct;
77
import org.gvsig.tools.dynobject.Tags;
78
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
79
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
80
import org.gvsig.tools.dynobject.exception.DynMethodException;
81
import org.gvsig.tools.dynobject.impl.DefaultTags;
82
import org.gvsig.tools.evaluator.AbstractEvaluator;
83
import org.gvsig.tools.evaluator.Evaluator;
84
import org.gvsig.tools.evaluator.EvaluatorData;
85
import org.gvsig.tools.evaluator.EvaluatorException;
86
import org.gvsig.tools.i18n.I18nManager;
87
import org.gvsig.tools.persistence.PersistenceManager;
88
import org.gvsig.tools.persistence.Persistent;
89
import org.gvsig.tools.persistence.PersistentState;
90
import org.gvsig.tools.persistence.exception.PersistenceException;
91
import org.slf4j.Logger;
92
import org.slf4j.LoggerFactory;
93
import org.gvsig.tools.dataTypes.CoercionContext;
94
import org.gvsig.tools.dataTypes.DataType.NumberPrecisionAndScale;
95
import org.gvsig.tools.util.GetItemWithSize;
96
import org.gvsig.tools.util.LabeledValue;
97

    
98
@SuppressWarnings("UseSpecificCatch")
99
public class DefaultFeatureAttributeDescriptor implements
100
        FeatureAttributeDescriptor, Persistent, DynField_v2, DynField_LabelAttribute {
101

    
102
  protected static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeatureAttributeDescriptor.class);
103

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

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

    
153
  protected CoercionContext coerceContext = null; // not persistent
154
  protected MathContext mathContext = null; // not persistent
155

    
156
  private int relationType = RELATION_TYPE_NONE;
157
  protected Locale locale;
158
  protected int displaySize;
159

    
160
  public DefaultFeatureAttributeDescriptor() {
161
    // Usada en la persistencia
162
    this.precision = DataType.PRECISION_NONE;
163
    this.scale = DataType.SCALE_NONE;
164
    this.roundMode = BigDecimal.ROUND_HALF_UP;
165
  }
166

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

    
198
  protected DefaultFeatureAttributeDescriptor(
199
          DefaultFeatureAttributeDescriptor other
200
  ) {
201
    this();
202
    copyFrom(other);
203
//        LOGGER.info(String.format("Created FeatureAttributeDescriptor [%08x] [%s] (copy).", this.hashCode(), this.name));
204
  }
205

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

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

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

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

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

    
306
  @Override
307
  public DefaultFeatureAttributeDescriptor getCopy() {
308
    return new DefaultFeatureAttributeDescriptor(this);
309
  }
310

    
311
  @Override
312
  public Object clone() throws CloneNotSupportedException {
313
    return new DefaultFeatureAttributeDescriptor(this);
314
  }
315

    
316
  @Override
317
  public boolean allowNull() {
318
    return allowNull;
319
  }
320

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

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

    
341
  public FeatureAttributeDescriptor setDataType(int type) {
342
    this.dataType = ToolsLocator.getDataTypesManager().get(type);
343
    return this;
344
  }
345

    
346
  @Override
347
  public DateFormat getDateFormat() {
348
    return this.dateFormat;
349
  }
350

    
351
  @Override
352
  public Object getDefaultValue() {
353
    return this.defaultValue;
354
  }
355

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

    
372
  @Override
373
  public Evaluator getEvaluator() {
374
    return this.evaluator;
375
  }
376

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

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

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

    
413
  @Override
414
  public int getIndex() {
415
    return this.index;
416
  }
417

    
418
  protected FeatureAttributeDescriptor setIndex(int index) {
419
    this.index = index;
420
    return this;
421
  }
422

    
423
  @Override
424
  public int getMaximumOccurrences() {
425
    return this.maximumOccurrences;
426
  }
427

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

    
433
  @Override
434
  public String getName() {
435
    return this.name;
436
  }
437

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

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

    
452
  @Override
453
  public int getPrecision() {
454
    return this.precision;
455
  }
456

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

    
462
  @Override
463
  public Coercion getCoercion() {
464
    return this.getDataType().getCoercion();
465
  }
466

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

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

    
501
  @Override
502
  public int getRoundMode() {
503
    return this.roundMode;
504
  }
505

    
506
  @Override
507
  public IProjection getSRS() {
508
    return this.SRS;
509
  }
510

    
511
  @Override
512
  public Interval getInterval() {
513
    return this.interval;
514
  }
515

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

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

    
529
  @Override
530
  public boolean isPrimaryKey() {
531
    return this.primaryKey;
532
  }
533

    
534
  @Override
535
  public boolean isReadOnly() {
536
    if (this.readOnly) {
537
      return true;
538
    }
539
    return this.isComputed();
540
  }
541

    
542
  @Override
543
  public Object getAdditionalInfo(String infoName) {
544
    if (this.additionalInfo == null) {
545
      return null;
546
    }
547
    return this.additionalInfo.get(infoName);
548
  }
549

    
550
  @Override
551
  public boolean isAutomatic() {
552
    return this.isAutomatic;
553
  }
554

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

    
566
    if (this.allowNull != other.allowNull) {
567
      return false;
568
    }
569

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

    
574
    if (!Objects.equals(this.name, other.name)) {
575
      return false;
576
    }
577

    
578
    if (this.getDataType() != other.getDataType()) {
579
      return false;
580
    }
581

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

    
586
    if (!Objects.equals(this.defaultValue, other.defaultValue)) {
587
      return false;
588
    }
589

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

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

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

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

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

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

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

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

    
622
    if (!Objects.equals(this.evaluator, other.evaluator)) {
623
      return false;
624
    }
625

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

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

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

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

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

    
646
    return true;
647
  }
648

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

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

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

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

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

    
728
    foreingKey = (DefaultForeingKey) state.get("foreingKey");
729
    if (foreingKey != null) {
730
      this.foreingKey.setDescriptor(this);
731
    }
732
    tags = (Tags) state.get("tags");
733
    if (tags == null) {
734
      this.tags = new DefaultTags();
735
    }
736
    displaySize = state.getInt("displaySize",0);
737
    availableValuesExpression = (Expression) state.get("availableValuesExpression");
738
    availableValuesCache = null;
739
  }
740

    
741
  @Override
742
  public void saveToState(PersistentState state) throws PersistenceException {
743
    Coercion toString = ToolsLocator.getDataTypesManager().getCoercion(DataTypes.STRING);
744
    
745
    state.set("allowNull", allowNull);
746
    state.set("dataType", dataType.getType());
747
    state.set("dataProfile", dataProfile);
748

    
749
//        FIXME: dateFormat;
750
    state.set("defaultValue", Objects.toString(defaultValue, null));
751

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

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

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

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

    
803
    state.set("indexed", indexed);
804
    state.set("isIndexAscending", isIndexAscending);
805
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
806

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

    
825
    state.set("foreingKey", this.foreingKey);
826
    state.set("tags", this.tags);
827

    
828
    state.set("displaySize", displaySize);
829
    state.set("availableValuesExpression", availableValuesExpression);
830
  }
831

    
832
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
833

    
834
  public static void registerPersistenceDefinition() {
835
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
836

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

    
889
      definition.addDynFieldObject("foreingKey")
890
              .setClassOfValue(DefaultForeingKey.class);
891

    
892
      definition.addDynFieldObject("tags")
893
              .setClassOfValue(Tags.class);
894

    
895
      definition.addDynFieldInt("displaySize").setMandatory(false);
896
      definition.addDynFieldObject("availableValuesExpression")
897
              .setClassOfValue(Expression.class)
898
              .setMandatory(false);
899
    }
900
  }
901

    
902
  /*
903
     * Start of DynField interface Implementation
904
     *
905
   */
906
  @Override
907
  public Tags getTags() {
908
    return tags;
909
  }
910

    
911
  @Override
912
  public boolean hasConstantAvailableValues() {
913
    return this.availableValues != null;
914
  }
915

    
916
  @Override
917
  public DynObjectValueItem[] getAvailableValues() {
918
    if (this.availableValues != null) {
919
        return this.availableValues;
920
    }
921
    if (this.availableValuesCache != null) {
922
        return this.availableValuesCache;
923
    }
924
    if (this.isForeingKey() && this.foreingKey.isClosedList()) {
925
      this.availableValuesCache = this.foreingKey.getAvailableValues(null);
926

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

    
1068
  private DynObjectValueItem[] getAvailableValuesFromExpression() {
1069
      if( this.availableValuesExpression == null || this.availableValuesExpression.isEmpty() ) {
1070
          return null;
1071
      }
1072
      try {
1073
        Object value = this.availableValuesExpression.execute(null);
1074
        if( value instanceof DynObjectValueItem[] ) {
1075
            return (DynObjectValueItem[]) value;
1076
        }
1077
        if( value instanceof List ) {
1078
            return this.getAvailableValuesFrom(new GetItemWithSize() {
1079
                @Override
1080
                public Object get(int i) {
1081
                    return ((List)value).get(i);
1082
                }
1083

    
1084
                @Override
1085
                public int size() {
1086
                    return ((List)value).size();
1087
                }
1088
            });
1089
        }
1090
      } catch(Throwable th) {
1091
          LOGGER.warn("Can't get available values from expression", th);
1092
      }
1093
      return null;
1094
  }
1095

    
1096
  @Override
1097
  public Expression getAvailableValuesExpression() {
1098
      return this.availableValuesExpression;
1099
  }
1100
  
1101
  @Override
1102
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1103
        if (StringUtils.isBlank(expression)) {
1104
            this.availableValuesExpression = null;
1105
            return this;
1106
        }
1107
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1108
        return this;
1109
    }
1110

    
1111
  @Override
1112
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1113
        this.availableValuesExpression = expression;
1114
        return this;
1115
    }
1116
  
1117
  @Override
1118
  public String getLabelOfValue(Object value) {
1119
    if (this.labelOfValueMap != null) {
1120
      String theLabel = this.labelOfValueMap.get(value);
1121
      if (theLabel == null) {
1122
        theLabel = Objects.toString(value, "");
1123
      }
1124
      return theLabel;
1125
    }
1126
    DynObjectValueItem[] values = this.getAvailableValues();
1127
    if (values == null) {
1128
      return Objects.toString(value, "");
1129
    }
1130
    Map<Object, String> map = new LinkedHashMap<>();
1131
    for (DynObjectValueItem theValue : values) {
1132
      map.put(theValue.getValue(), theValue.getLabel());
1133
    }
1134
    this.labelOfValueMap = map;
1135
    String theLabel = this.labelOfValueMap.get(value);
1136
    if (theLabel == null) {
1137
      theLabel = Objects.toString(value, "");
1138
    }
1139
    return theLabel;
1140
  }
1141

    
1142
  @Override
1143
  public String getDescription() {
1144
    if (this.description == null) {
1145
      return getName();
1146
    }
1147
    return this.description;
1148
  }
1149

    
1150
  @Override
1151
  public Object getMaxValue() {
1152
    return this.maxValue;
1153
  }
1154

    
1155
  @Override
1156
  public Object getMinValue() {
1157
    return this.minValue;
1158
  }
1159

    
1160
  @Override
1161
  public int getTheTypeOfAvailableValues() {
1162
    return 1;
1163
  }
1164

    
1165
  @Override
1166
  public int getType() {
1167
    if (featureAttributeGetter != null) {
1168
      return featureAttributeGetter.getDataType().getType();
1169
    }
1170
    return getDataType().getType();
1171
  }
1172

    
1173
  @Override
1174
  public boolean isMandatory() {
1175
    return !allowNull() || isPrimaryKey();
1176
  }
1177

    
1178
  @Override
1179
  public boolean isPersistent() {
1180
    return false;
1181
  }
1182

    
1183
  @Override
1184
  public DynField setAvailableValues(DynObjectValueItem[] values) {
1185
    if (ArrayUtils.isEmpty(values)) {
1186
      this.availableValues = null;
1187
    } else {
1188
      this.availableValues = values;
1189
    }
1190
    return this;
1191
  }
1192

    
1193
  @Override
1194
  public DynField setDescription(String description) {
1195
    this.description = description;
1196
    return this;
1197
  }
1198

    
1199
  @Override
1200
  public DynField setMandatory(boolean mandatory) {
1201
    throw new UnsupportedOperationException();
1202
  }
1203

    
1204
  @Override
1205
  public DynField setMaxValue(Object maxValue) {
1206
    try {
1207
      this.maxValue = this.coerce(maxValue);
1208
    } catch (CoercionException e) {
1209
      throw new IllegalArgumentException(e);
1210
    }
1211
    return this;
1212
  }
1213

    
1214
  @Override
1215
  public DynField setMinValue(Object minValue) {
1216
    try {
1217
      this.maxValue = this.coerce(minValue);
1218
    } catch (CoercionException e) {
1219
      throw new IllegalArgumentException(e);
1220
    }
1221
    return this;
1222
  }
1223

    
1224
  @Override
1225
  public DynField setPersistent(boolean persistent) {
1226
    throw new UnsupportedOperationException();
1227
  }
1228

    
1229
  @Override
1230
  public DynField setTheTypeOfAvailableValues(int type) {
1231
    throw new UnsupportedOperationException();
1232
  }
1233

    
1234
  @Override
1235
  public DynField setType(int type) {
1236
    throw new UnsupportedOperationException();
1237
  }
1238

    
1239
  @Override
1240
  public DynField setDefaultDynValue(Object defaultValue) {
1241
    throw new UnsupportedOperationException();
1242
  }
1243

    
1244
  @Override
1245
  public Class getClassOfValue() {
1246
    return null;
1247
  }
1248

    
1249
  @Override
1250
  public DynField getElementsType() {
1251
    return null;
1252
  }
1253

    
1254
  @Override
1255
  public DynField setClassOfValue(Class theClass)
1256
          throws DynFieldIsNotAContainerException {
1257
    throw new UnsupportedOperationException();
1258
  }
1259

    
1260
  @Override
1261
  public DynField setElementsType(DynStruct type)
1262
          throws DynFieldIsNotAContainerException {
1263
    throw new UnsupportedOperationException();
1264
  }
1265

    
1266
  @Override
1267
  public DynField setElementsType(int type)
1268
          throws DynFieldIsNotAContainerException {
1269
    throw new UnsupportedOperationException();
1270
  }
1271

    
1272
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1273
    this.dataProfile = dataProfile;
1274
    return this;
1275
  }
1276

    
1277
  @Override
1278
  public String getDataProfileName() {
1279
    return dataProfile;
1280
  }
1281

    
1282
  @Override
1283
  public DataProfile getDataProfile() {
1284
    if (StringUtils.isBlank(dataProfile)) {
1285
      return null;
1286
    }
1287
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1288
    return profile;
1289
  }
1290

    
1291
  @Override
1292
  public void validate(Object value) throws DynFieldValidateException {
1293

    
1294
    if (value == null && !this.allowNull()) {
1295
      throw new DynFieldValidateException(value, this, null);
1296
    }
1297

    
1298
    try {
1299
      this.dataType.coerce(value);
1300
    } catch (CoercionException e) {
1301
      throw new DynFieldValidateException(value, this, e);
1302
    }
1303

    
1304
    /*
1305
         * Other checks will be needed
1306
     */
1307
  }
1308

    
1309
  @Override
1310
  public String getSubtype() {
1311
    if (featureAttributeGetter != null) {
1312
      return featureAttributeGetter.getDataType().getSubtype();
1313
    }
1314
    return this.dataType.getSubtype();
1315
  }
1316

    
1317
  @Override
1318
  public Object coerce(Object value) throws CoercionException {
1319
    if (value == null) {
1320
      return value; // O debe devolver this.defaultValue
1321
    }
1322
    try {
1323
      return this.getDataType().coerce(value, this.getCoercionContext());
1324
    } catch (Exception ex) {
1325
      throw new RuntimeException(ex);
1326
    }
1327
  }
1328

    
1329
  @Override
1330
  public DynField setAvailableValues(List values) {
1331
    if (values == null || values.isEmpty()) {
1332
      this.availableValues = null;
1333
    } else {
1334
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1335
              new DynObjectValueItem[values.size()]
1336
      );
1337
    }
1338
    return this;
1339
  }
1340

    
1341
  @Override
1342
  public String getGroup() {
1343
    return this.groupName;
1344
  }
1345

    
1346
  @Override
1347
  public int getOder() {
1348
    return this.order;
1349
  }
1350

    
1351
  @Override
1352
  public String getLabel() {
1353
    if (this.label == null) {
1354
      return this.getName();
1355
    }
1356
    return this.label;
1357
  }
1358

    
1359
  @Override
1360
  public String getLocalizedLabel() {
1361
    if (StringUtils.isBlank(this.label)) {
1362
      return this.getName();
1363
    }
1364
    I18nManager i18n = ToolsLocator.getI18nManager();
1365
    return i18n.getTranslation(this.label);
1366
  }
1367

    
1368
  @Override
1369
  public DynField setLabel(String label) {
1370
    this.label = label;
1371
    return this;
1372
  }
1373

    
1374
  @Override
1375
  public DynField setShortLabel(String shortLabel) {
1376
    this.shortLabel = shortLabel;
1377
    return this;
1378
  }
1379

    
1380
  @Override
1381
  public String getShortLabel() {
1382
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1383
  }
1384

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

    
1394
  @Override
1395
  public DynField setGroup(String groupName) {
1396
    this.groupName = groupName;
1397
    return this;
1398
  }
1399

    
1400
  @Override
1401
  public DynField setOrder(int order) {
1402
    this.order = order;
1403
    return this;
1404
  }
1405

    
1406
  @Override
1407
  public DynField setHidden(boolean hidden) {
1408
    this.hidden = hidden;
1409
    return this;
1410
  }
1411

    
1412
  @Override
1413
  public boolean isHidden() {
1414
    return this.hidden;
1415
  }
1416

    
1417
  @Override
1418
  public DynField setReadOnly(boolean readOnly) {
1419
    this.readOnly = readOnly;
1420
    return this;
1421
  }
1422

    
1423
  @Override
1424
  public boolean isContainer() {
1425
    return false;
1426
  }
1427

    
1428
  @Override
1429
  public Class getClassOfItems() {
1430
    return null;
1431
  }
1432

    
1433
  @Override
1434
  public DynField setDefaultFieldValue(Object defaultValue) {
1435
    throw new UnsupportedOperationException();
1436
  }
1437

    
1438
  @Override
1439
  public DynField setClassOfItems(Class theClass) {
1440
    throw new UnsupportedOperationException();
1441
  }
1442

    
1443
  @Override
1444
  public DynField setType(DataType type) {
1445
    throw new UnsupportedOperationException();
1446
  }
1447

    
1448
  @Override
1449
  public DynField setSubtype(String subtype) {
1450
    throw new UnsupportedOperationException();
1451
  }
1452

    
1453
  @Override
1454
  public boolean isTime() {
1455
    return isTime;
1456
  }
1457

    
1458
  @Override
1459
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1460
    return featureAttributeGetter;
1461
  }
1462

    
1463
  @Override
1464
  public void setFeatureAttributeGetter(
1465
          FeatureAttributeGetter featureAttributeTransform) {
1466
    this.featureAttributeGetter = featureAttributeTransform;
1467
  }
1468

    
1469
  @Override
1470
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1471
    return this.featureAttributeEmulator;
1472
  }
1473

    
1474
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1475
    this.featureAttributeEmulator = featureAttributeEmulator;
1476
    return this;
1477
  }
1478

    
1479
  @Override
1480
  public boolean isIndexed() {
1481
    return this.indexed;
1482
  }
1483

    
1484
  @Override
1485
  public boolean isForeingKey() {
1486
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1487
  }
1488

    
1489
  @Override
1490
  public ForeingKey getForeingKey() {
1491
    return this.foreingKey;
1492
  }
1493

    
1494
  @Override
1495
  public boolean allowIndexDuplicateds() {
1496
    return this.allowIndexDuplicateds;
1497
  }
1498

    
1499
  @Override
1500
  public boolean isIndexAscending() {
1501
    return this.isIndexAscending;
1502
  }
1503

    
1504
  @Override
1505
  public DynField setClassOfValue(DynStruct dynStrct) {
1506
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1507
  }
1508

    
1509
  @Override
1510
  public DynField setClassOfValue(String theClassNameOfValue) {
1511
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1512
  }
1513

    
1514
  @Override
1515
  public String getClassNameOfValue() {
1516
    return null;
1517
  }
1518

    
1519
  @Override
1520
  public DynStruct getDynClassOfValue() {
1521
    return null;
1522
  }
1523

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

    
1529
  @Override
1530
  public int getTypeOfItems() {
1531
    return DataTypes.INVALID;
1532
  }
1533

    
1534
  @Override
1535
  public DynField setClassOfItems(DynStruct dynStrct) {
1536
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1537
  }
1538

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

    
1544
  @Override
1545
  public String getClassNameOfItems() {
1546
    return null;
1547
  }
1548

    
1549
  @Override
1550
  public DynStruct getDynClassOfItems() {
1551
    return null;
1552
  }
1553

    
1554
  @Override
1555
  public DynField setRelationType(int relationType) {
1556
    this.relationType = relationType;
1557
    return this;
1558
  }
1559

    
1560
  @Override
1561
  public int getRelationType() {
1562
    return this.relationType;
1563
  }
1564

    
1565
  @Override
1566
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1567
    this.availableValuesMethod = availableValuesMethod;
1568
    return this;
1569
  }
1570

    
1571
  @Override
1572
  public DynObjectValueItem[] getAvailableValues(DynObject self) {
1573
    if (this.availableValuesMethod != null) {
1574
      DynObjectValueItem[] values;
1575
      try {
1576
        values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self, new Object[]{this});
1577
      } catch (DynMethodException ex) {
1578
        return this.availableValues;
1579
      }
1580
      if (values != null) {
1581
        return values;
1582
      }
1583
    }
1584
    return this.availableValues;
1585
  }
1586

    
1587
  @Override
1588
  public DynMethod getAvailableValuesMethod() {
1589
    return this.availableValuesMethod;
1590
  }
1591

    
1592
  @Override
1593
  public boolean isAvailableValuesCalculated() {
1594
    return this.availableValuesMethod != null;
1595
  }
1596

    
1597
  @Override
1598
  public DynMethod getCalculateMethod() {
1599
    return this.calculateMethod;
1600
  }
1601

    
1602
  @Override
1603
  public DynField setCalculateMethod(DynMethod method) {
1604
    this.calculateMethod = method;
1605
    return this;
1606
  }
1607

    
1608
  @Override
1609
  public boolean isCalculated() {
1610
    return this.calculateMethod != null;
1611
  }
1612

    
1613
  @Override
1614
  public Object getCalculatedValue(DynObject self) {
1615
    try {
1616
      return this.calculateMethod.invoke(self, new Object[]{this});
1617
    } catch (DynMethodException ex) {
1618
      throw new RuntimeException(ex);
1619
    }
1620
  }
1621

    
1622
  @Override
1623
  public DynField setValidateElements(boolean validate) {
1624
    return this;
1625
  }
1626

    
1627
  @Override
1628
  public boolean getValidateElements() {
1629
    return false;
1630
  }
1631

    
1632
  @Override
1633
  public boolean hasLabel() {
1634
    return StringUtils.isNotBlank(this.label);
1635
  }
1636

    
1637
  @Override
1638
  public boolean hasShortLabel() {
1639
    return StringUtils.isNotBlank(this.shortLabel);
1640
  }
1641

    
1642
  @Override
1643
  public boolean hasDescription() {
1644
    return StringUtils.isNotBlank(this.description);
1645
  }
1646

    
1647
  @Override
1648
  public FeatureAttributeDescriptor getValue() {
1649
    return this;
1650
  }
1651

    
1652
  @Override
1653
  public int getDisplaySize() {
1654
    return this.displaySize;
1655
  }
1656

    
1657
  private class ConstantValueEvaluator extends AbstractEvaluator {
1658

    
1659
    @Override
1660
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1661
      return defaultValue;
1662
    }
1663

    
1664
    @Override
1665
    public String getName() {
1666
      return "Constant attribute " + name;
1667
    }
1668
  }
1669

    
1670
  public void setConstantValue(boolean isConstantValue) {
1671
    if (isConstantValue) {
1672
      /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1673
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1674
             * el evaluador el que se encarga de proporcionar su valor.
1675
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1676
             * por defecto para ese attributo.
1677
       */
1678
      this.evaluator = new ConstantValueEvaluator();
1679
    } else {
1680
      this.evaluator = null;
1681
    }
1682
  }
1683

    
1684
  @Override
1685
  public boolean isComputed() {
1686
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1687
  }
1688

    
1689
  @Override
1690
  public FeatureStore getStore() {
1691
    FeatureType ftype = this.getFeatureType();
1692
    if (ftype == null) {
1693
      return null;
1694
    }
1695
    return ftype.getStore();
1696
  }
1697

    
1698
  @Override
1699
  public FeatureType getFeatureType() {
1700
    if (this.typeRef == null) {
1701
      return null;
1702
    }
1703
    FeatureType ftype = (FeatureType) this.typeRef.get();
1704
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1705
    return ftype;
1706
  }
1707

    
1708
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1709
    this.interval = interval;
1710
    return this;
1711
  }
1712

    
1713
  public void fixAll() {
1714
    if (!this.getDataType().supportSize()) {
1715
      this.size = 0;
1716
    }
1717
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1718
    this.precision = ps.getPrecision();
1719
    this.scale = ps.getScale();
1720

    
1721
    switch (this.getType()) {
1722
      case DataTypes.INSTANT:
1723
      case DataTypes.INTERVAL:
1724
      case DataTypes.DATE:
1725
      case DataTypes.TIME:
1726
      case DataTypes.TIMESTAMP:
1727
        if (this.getInterval() != null) {
1728
          this.isTime = true;
1729
        }
1730
        break;
1731
    }
1732
  }
1733

    
1734
  @Override
1735
  public String[] getRequiredFieldNames() {
1736
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1737
    if (emulator == null) {
1738
      return null;
1739
    }
1740
    return emulator.getRequiredFieldNames();
1741
  }
1742

    
1743
  @Override
1744
  public void recentUsed() {
1745
    DefaultFeatureType.RECENTS_USEDS.add(this);
1746
  }
1747

    
1748
  @Override
1749
  public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1750
    if (other == null) {
1751
      throw new NullPointerException();
1752
    }
1753
    DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1754
    if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1755
      return false;
1756
    }
1757
    if (old.isComputed() && old.isComputed() == this.isComputed()) {
1758
      return true;
1759
    }
1760
    if (this.dataType != old.dataType) {
1761
      return false;
1762
    }
1763
    if (this.size != old.size) {
1764
      return false;
1765
    }
1766
    if (this.precision != old.precision) {
1767
      return false;
1768
    }
1769
//        if( this.primaryKey != old.primaryKey ) {
1770
//            return false;
1771
//        }
1772
    if (this.geomType != old.geomType) {
1773
      return false;
1774
    }
1775
    if (this.SRS != old.SRS) {
1776
      return false;
1777
    }
1778
    if (this.isAutomatic != old.isAutomatic) {
1779
      return false;
1780
    }
1781
    return true;
1782
  }
1783
  
1784
  private class PropertiesBuilder {
1785

    
1786
        private String name;
1787
        private DataType type;
1788
        private Map<String,String> sets;
1789
        private String sep;
1790
      
1791
      public PropertiesBuilder() {
1792
          this.sets = new LinkedHashMap<>();
1793
      }
1794
      
1795
      public void separator(String sep) {
1796
          this.sep = sep;
1797
      }
1798
      
1799
      public void name(String name) {
1800
        this.name = name;
1801
      }
1802
      
1803
      public void type(DataType type) {
1804
          this.type = type;
1805
      }
1806
      
1807
      public void set(String name, ForeingKey fk) {
1808
          if( fk == null ) {
1809
              return;
1810
          }
1811
          if( !fk.isForeingKey() ) {
1812
              return;
1813
          }
1814
          this.set(name, fk.isForeingKey());
1815
          this.set(name+"_code", fk.getCodeName());
1816
          this.set(name+"_label", fk.getLabelFormula());
1817
          this.set(name+"_closedlist", fk.isClosedList());
1818
          this.set(name+"_table", fk.getTableName());
1819
      }
1820

    
1821
      public void set(String name, FeatureAttributeEmulator value) {
1822
          if( value == null ) {
1823
              return;
1824
          }
1825
          if( value instanceof FeatureAttributeEmulatorExpression ) {
1826
            this.set(name, ((FeatureAttributeEmulatorExpression)value).getExpression().getPhrase());
1827
          }
1828
      }
1829
      
1830
      public void set(String name, IProjection value) {
1831
          if( value == null ) {
1832
              return;
1833
          }
1834
          this.set(name, value.getAbrev());
1835
      }
1836
      
1837
      public void set(String name, GeometryType value) {
1838
          if( value == null ) {
1839
              return;
1840
          }
1841
          this.set(name, value.getFullName().replace(":", "@"));
1842
      }
1843
      
1844
      public void set(String name, Object value) {
1845
          if( value == null ) {
1846
              return;
1847
          }
1848
          String s = Objects.toString(value, "");
1849
          if( StringUtils.isBlank(s) ) {
1850
              return;
1851
          }
1852
          this.sets.put(name, s);
1853
      }
1854
      
1855
      @Override
1856
      public String toString() {        
1857
        StringBuilder builder = new StringBuilder();
1858
        builder.append(this.name);
1859
        builder.append(sep);        
1860
        builder.append(this.type.getName());
1861
        for (String key : this.sets.keySet()) {
1862
            builder.append(sep);        
1863
            builder.append("set");
1864
            builder.append(sep);        
1865
            builder.append(key);        
1866
            builder.append("=");        
1867
            builder.append(this.sets.get(key));                    
1868
        }
1869
        return builder.toString();
1870
      }
1871
  }
1872

    
1873
  private String getAll() {
1874
    PropertiesBuilder builder = new PropertiesBuilder();
1875
    builder.separator("__");
1876
    builder.name(this.name);
1877
    builder.type(this.dataType);
1878
    builder.set("size", this.size);
1879
    builder.set("precision", this.precision);
1880
    builder.set("scale", this.scale);
1881
    builder.set("hidden", this.isHidden());
1882
    builder.set("readOnly", this.isReadOnly());
1883
    builder.set("allowNull", this.allowNull());
1884
    builder.set("pk", this.isPrimaryKey());
1885
    builder.set("automatic", this.isAutomatic());
1886
    builder.set("isTime", this.isTime());
1887
    builder.set("profile", this.getDataProfileName());
1888
    builder.set("group", this.getGroup());
1889
    builder.set("description", this.description);
1890
    builder.set("label", this.label);
1891
    builder.set("shortLabel", this.shortLabel);
1892
    builder.set("locale", this.getLocale());
1893
    builder.set("order", this.getOder());
1894
    builder.set("roundMode", this.getRoundMode());
1895
    builder.set("srs", this.getSRS());
1896
    builder.set("geomtype", this.getGeomType());
1897
    builder.set("expression", this.getFeatureAttributeEmulator());
1898
    builder.set("fk", this.getForeingKey());
1899
    return builder.toString();
1900
  }
1901
  
1902
  @Override
1903
  public Object get(String name) {
1904
    if (StringUtils.isBlank(name)) {
1905
      throw new IllegalArgumentException("Name can't be empty");
1906
    }
1907
    switch (name.trim().toLowerCase()) {
1908
      case "all":
1909
          return this.getAll();
1910
      case "isreadonly":
1911
      case "readonly":
1912
        return this.isReadOnly();
1913
      case "hidden":
1914
        return this.isHidden();
1915
      case "allownull":
1916
        return this.allowNull();
1917
      case "pk":
1918
      case "ispk":
1919
      case "primarykey":
1920
      case "isprimarykey":
1921
        return this.isPrimaryKey();
1922
      case "isautomatic":
1923
      case "automatic":
1924
        return this.isAutomatic();
1925
      case "time":
1926
      case "istime":
1927
        return this.isTime();
1928
      case "profile":
1929
        return this.getDataProfile();
1930
      case "group":
1931
        return this.getGroup();
1932
      case "description":
1933
        return this.getDescription();
1934
      case "label":
1935
        return this.getLabel();
1936
      case "shortlabel":
1937
        return this.getShortLabel();
1938
      case "expression":
1939
        return this.getFeatureAttributeEmulator();
1940
      case "size":
1941
        return this.getSize();
1942
      case "precision":
1943
        return this.getPrecision();
1944
      case "scale":
1945
        return this.getScale();
1946
      case "roundmode":
1947
        return this.getRoundMode();
1948
      case "locale":
1949
        return this.getLocale();
1950
      case "order":
1951
        return this.getOder();
1952
      case "foreingkey":
1953
        return this.getForeingKey();
1954
      case "interval":
1955
        return this.getInterval();
1956
      case "geomtype":
1957
      case "geometrytype":
1958
        return this.getGeomType();
1959
      case "srs":
1960
        return this.getSRS();
1961
      default:
1962
        throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
1963
    }
1964
  }
1965
  
1966
    public void setSRSForced(IProjection SRS) {
1967
        this.SRS = SRS;
1968
    }
1969
    
1970
}