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

History | View | Annotate | Download (53 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.feature.DataProfile;
49
import org.gvsig.fmap.dal.feature.Feature;
50
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
53
import org.gvsig.fmap.dal.feature.FeatureStore;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.fmap.dal.feature.ForeingKey;
56
import org.gvsig.fmap.geom.Geometry;
57
import org.gvsig.fmap.geom.GeometryException;
58
import org.gvsig.fmap.geom.GeometryLocator;
59
import org.gvsig.fmap.geom.GeometryUtils;
60
import org.gvsig.fmap.geom.type.GeometryType;
61
import org.gvsig.timesupport.Interval;
62
import org.gvsig.timesupport.RelativeInterval;
63
import org.gvsig.timesupport.TimeSupportLocator;
64
import org.gvsig.tools.ToolsLocator;
65
import org.gvsig.tools.dataTypes.Coercion;
66
import org.gvsig.tools.dataTypes.CoercionException;
67
import org.gvsig.tools.dataTypes.DataType;
68
import org.gvsig.tools.dataTypes.DataTypeUtils;
69
import org.gvsig.tools.dynobject.DynField;
70
import org.gvsig.tools.dynobject.DynField_LabelAttribute;
71
import org.gvsig.tools.dynobject.DynField_v2;
72
import org.gvsig.tools.dynobject.DynMethod;
73
import org.gvsig.tools.dynobject.DynObject;
74
import org.gvsig.tools.dynobject.DynObjectValueItem;
75
import org.gvsig.tools.dynobject.DynStruct;
76
import org.gvsig.tools.dynobject.Tags;
77
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
78
import org.gvsig.tools.dynobject.exception.DynFieldValidateException;
79
import org.gvsig.tools.dynobject.exception.DynMethodException;
80
import org.gvsig.tools.dynobject.impl.DefaultTags;
81
import org.gvsig.tools.evaluator.AbstractEvaluator;
82
import org.gvsig.tools.evaluator.Evaluator;
83
import org.gvsig.tools.evaluator.EvaluatorData;
84
import org.gvsig.tools.evaluator.EvaluatorException;
85
import org.gvsig.tools.i18n.I18nManager;
86
import org.gvsig.tools.persistence.PersistenceManager;
87
import org.gvsig.tools.persistence.Persistent;
88
import org.gvsig.tools.persistence.PersistentState;
89
import org.gvsig.tools.persistence.exception.PersistenceException;
90
import org.slf4j.Logger;
91
import org.slf4j.LoggerFactory;
92
import org.gvsig.tools.dataTypes.CoercionContext;
93
import org.gvsig.tools.dataTypes.DataType.NumberPrecisionAndScale;
94
import org.gvsig.tools.util.GetItemWithSize;
95
import org.gvsig.tools.util.LabeledValue;
96

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
314
  @Override
315
  public boolean allowNull() {
316
    return allowNull;
317
  }
318

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
644
    return true;
645
  }
646

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

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

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

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

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

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

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

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

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

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

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

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

    
801
    state.set("indexed", indexed);
802
    state.set("isIndexAscending", isIndexAscending);
803
    state.set("allowIndexDuplicateds", allowIndexDuplicateds);
804

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

    
823
    state.set("foreingKey", this.foreingKey);
824
    state.set("tags", this.tags);
825

    
826
    state.set("displaySize", displaySize);
827
    state.set("availableValuesExpression", availableValuesExpression);
828
  }
829

    
830
  private static final String FEATATTRDESC_PERSISTENCE_DEFINITION_NAME = "FeatureAttributeDescriptor";
831

    
832
  public static void registerPersistenceDefinition() {
833
    PersistenceManager manager = ToolsLocator.getPersistenceManager();
834

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

    
887
      definition.addDynFieldObject("foreingKey")
888
              .setClassOfValue(DefaultForeingKey.class);
889

    
890
      definition.addDynFieldObject("tags")
891
              .setClassOfValue(Tags.class);
892

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

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

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

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

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

    
1030
  private DynObjectValueItem[] getAvailableValuesFromExpression() {
1031
      if( this.availableValuesExpression == null || this.availableValuesExpression.isEmpty() ) {
1032
          return null;
1033
      }
1034
      Object value = this.availableValuesExpression.execute(null);
1035
      if( value instanceof DynObjectValueItem[] ) {
1036
          return (DynObjectValueItem[]) value;
1037
      }
1038
      if( value instanceof List ) {
1039
          return this.getAvailableValuesFrom(new GetItemWithSize() {
1040
              @Override
1041
              public Object get(int i) {
1042
                  return ((List)value).get(i);
1043
              }
1044

    
1045
              @Override
1046
              public int size() {
1047
                  return ((List)value).size();
1048
              }
1049
          });
1050
      }
1051
      return null;
1052
  }
1053

    
1054
  @Override
1055
  public Expression getAvailableValuesExpression() {
1056
      return this.availableValuesExpression;
1057
  }
1058
  
1059
  @Override
1060
    public FeatureAttributeDescriptor setAvailableValuesExpression(String expression) {
1061
        if (StringUtils.isBlank(expression)) {
1062
            this.availableValuesExpression = null;
1063
            return this;
1064
        }
1065
        this.availableValuesExpression = ExpressionUtils.createExpression(expression);
1066
        return this;
1067
    }
1068

    
1069
  @Override
1070
    public FeatureAttributeDescriptor setAvailableValuesExpression(Expression expression) {
1071
        this.availableValuesExpression = expression;
1072
        return this;
1073
    }
1074
  
1075
  @Override
1076
  public String getLabelOfValue(Object value) {
1077
    if (this.labelOfValueMap != null) {
1078
      String theLabel = this.labelOfValueMap.get(value);
1079
      if (theLabel == null) {
1080
        theLabel = Objects.toString(value, "");
1081
      }
1082
      return theLabel;
1083
    }
1084
    DynObjectValueItem[] values = this.getAvailableValues();
1085
    if (values == null) {
1086
      return Objects.toString(value, "");
1087
    }
1088
    Map<Object, String> map = new LinkedHashMap<>();
1089
    for (DynObjectValueItem theValue : values) {
1090
      map.put(theValue.getValue(), theValue.getLabel());
1091
    }
1092
    this.labelOfValueMap = map;
1093
    String theLabel = this.labelOfValueMap.get(value);
1094
    if (theLabel == null) {
1095
      theLabel = Objects.toString(value, "");
1096
    }
1097
    return theLabel;
1098
  }
1099

    
1100
  @Override
1101
  public String getDescription() {
1102
    if (this.description == null) {
1103
      return getName();
1104
    }
1105
    return this.description;
1106
  }
1107

    
1108
  @Override
1109
  public Object getMaxValue() {
1110
    return this.maxValue;
1111
  }
1112

    
1113
  @Override
1114
  public Object getMinValue() {
1115
    return this.minValue;
1116
  }
1117

    
1118
  @Override
1119
  public int getTheTypeOfAvailableValues() {
1120
    return 1;
1121
  }
1122

    
1123
  @Override
1124
  public int getType() {
1125
    if (featureAttributeGetter != null) {
1126
      return featureAttributeGetter.getDataType().getType();
1127
    }
1128
    return getDataType().getType();
1129
  }
1130

    
1131
  @Override
1132
  public boolean isMandatory() {
1133
    return !allowNull() || isPrimaryKey();
1134
  }
1135

    
1136
  @Override
1137
  public boolean isPersistent() {
1138
    return false;
1139
  }
1140

    
1141
  @Override
1142
  public DynField setAvailableValues(DynObjectValueItem[] values) {
1143
    if (ArrayUtils.isEmpty(values)) {
1144
      this.availableValues = null;
1145
    } else {
1146
      this.availableValues = values;
1147
    }
1148
    return this;
1149
  }
1150

    
1151
  @Override
1152
  public DynField setDescription(String description) {
1153
    this.description = description;
1154
    return this;
1155
  }
1156

    
1157
  @Override
1158
  public DynField setMandatory(boolean mandatory) {
1159
    throw new UnsupportedOperationException();
1160
  }
1161

    
1162
  @Override
1163
  public DynField setMaxValue(Object maxValue) {
1164
    try {
1165
      this.maxValue = this.coerce(maxValue);
1166
    } catch (CoercionException e) {
1167
      throw new IllegalArgumentException(e);
1168
    }
1169
    return this;
1170
  }
1171

    
1172
  @Override
1173
  public DynField setMinValue(Object minValue) {
1174
    try {
1175
      this.maxValue = this.coerce(minValue);
1176
    } catch (CoercionException e) {
1177
      throw new IllegalArgumentException(e);
1178
    }
1179
    return this;
1180
  }
1181

    
1182
  @Override
1183
  public DynField setPersistent(boolean persistent) {
1184
    throw new UnsupportedOperationException();
1185
  }
1186

    
1187
  @Override
1188
  public DynField setTheTypeOfAvailableValues(int type) {
1189
    throw new UnsupportedOperationException();
1190
  }
1191

    
1192
  @Override
1193
  public DynField setType(int type) {
1194
    throw new UnsupportedOperationException();
1195
  }
1196

    
1197
  @Override
1198
  public DynField setDefaultDynValue(Object defaultValue) {
1199
    throw new UnsupportedOperationException();
1200
  }
1201

    
1202
  @Override
1203
  public Class getClassOfValue() {
1204
    return null;
1205
  }
1206

    
1207
  @Override
1208
  public DynField getElementsType() {
1209
    return null;
1210
  }
1211

    
1212
  @Override
1213
  public DynField setClassOfValue(Class theClass)
1214
          throws DynFieldIsNotAContainerException {
1215
    throw new UnsupportedOperationException();
1216
  }
1217

    
1218
  @Override
1219
  public DynField setElementsType(DynStruct type)
1220
          throws DynFieldIsNotAContainerException {
1221
    throw new UnsupportedOperationException();
1222
  }
1223

    
1224
  @Override
1225
  public DynField setElementsType(int type)
1226
          throws DynFieldIsNotAContainerException {
1227
    throw new UnsupportedOperationException();
1228
  }
1229

    
1230
  public FeatureAttributeDescriptor setDataProfileName(String dataProfile) {
1231
    this.dataProfile = dataProfile;
1232
    return this;
1233
  }
1234

    
1235
  @Override
1236
  public String getDataProfileName() {
1237
    return dataProfile;
1238
  }
1239

    
1240
  @Override
1241
  public DataProfile getDataProfile() {
1242
    if (StringUtils.isBlank(dataProfile)) {
1243
      return null;
1244
    }
1245
    DataProfile profile = DALLocator.getDataManager().getDataProfile(dataProfile);
1246
    return profile;
1247
  }
1248

    
1249
  @Override
1250
  public void validate(Object value) throws DynFieldValidateException {
1251

    
1252
    if (value == null && !this.allowNull()) {
1253
      throw new DynFieldValidateException(value, this, null);
1254
    }
1255

    
1256
    try {
1257
      this.dataType.coerce(value);
1258
    } catch (CoercionException e) {
1259
      throw new DynFieldValidateException(value, this, e);
1260
    }
1261

    
1262
    /*
1263
         * Other checks will be needed
1264
     */
1265
  }
1266

    
1267
  @Override
1268
  public String getSubtype() {
1269
    if (featureAttributeGetter != null) {
1270
      return featureAttributeGetter.getDataType().getSubtype();
1271
    }
1272
    return this.dataType.getSubtype();
1273
  }
1274

    
1275
  @Override
1276
  public Object coerce(Object value) throws CoercionException {
1277
    if (value == null) {
1278
      return value; // O debe devolver this.defaultValue
1279
    }
1280
    try {
1281
      return this.getDataType().coerce(value, this.getCoercionContext());
1282
    } catch (Exception ex) {
1283
      throw new RuntimeException(ex);
1284
    }
1285
  }
1286

    
1287
  @Override
1288
  public DynField setAvailableValues(List values) {
1289
    if (values == null || values.isEmpty()) {
1290
      this.availableValues = null;
1291
    } else {
1292
      this.availableValues = (DynObjectValueItem[]) values.toArray(
1293
              new DynObjectValueItem[values.size()]
1294
      );
1295
    }
1296
    return this;
1297
  }
1298

    
1299
  @Override
1300
  public String getGroup() {
1301
    return this.groupName;
1302
  }
1303

    
1304
  @Override
1305
  public int getOder() {
1306
    return this.order;
1307
  }
1308

    
1309
  @Override
1310
  public String getLabel() {
1311
    if (this.label == null) {
1312
      return this.getName();
1313
    }
1314
    return this.label;
1315
  }
1316

    
1317
  @Override
1318
  public String getLocalizedLabel() {
1319
    if (StringUtils.isBlank(this.label)) {
1320
      return this.getName();
1321
    }
1322
    I18nManager i18n = ToolsLocator.getI18nManager();
1323
    return i18n.getTranslation(this.label);
1324
  }
1325

    
1326
  @Override
1327
  public DynField setLabel(String label) {
1328
    this.label = label;
1329
    return this;
1330
  }
1331

    
1332
  @Override
1333
  public DynField setShortLabel(String shortLabel) {
1334
    this.shortLabel = shortLabel;
1335
    return this;
1336
  }
1337

    
1338
  @Override
1339
  public String getShortLabel() {
1340
    return StringUtils.isBlank(shortLabel) ? getLabel() : shortLabel;
1341
  }
1342

    
1343
  @Override
1344
  public String getLocalizedShortLabel() {
1345
    if (StringUtils.isBlank(shortLabel)) {
1346
      return this.getLocalizedLabel();
1347
    }
1348
    I18nManager i18n = ToolsLocator.getI18nManager();
1349
    return i18n.getTranslation(shortLabel);
1350
  }
1351

    
1352
  @Override
1353
  public DynField setGroup(String groupName) {
1354
    this.groupName = groupName;
1355
    return this;
1356
  }
1357

    
1358
  @Override
1359
  public DynField setOrder(int order) {
1360
    this.order = order;
1361
    return this;
1362
  }
1363

    
1364
  @Override
1365
  public DynField setHidden(boolean hidden) {
1366
    this.hidden = hidden;
1367
    return this;
1368
  }
1369

    
1370
  @Override
1371
  public boolean isHidden() {
1372
    return this.hidden;
1373
  }
1374

    
1375
  @Override
1376
  public DynField setReadOnly(boolean readOnly) {
1377
    this.readOnly = readOnly;
1378
    return this;
1379
  }
1380

    
1381
  @Override
1382
  public boolean isContainer() {
1383
    return false;
1384
  }
1385

    
1386
  @Override
1387
  public Class getClassOfItems() {
1388
    return null;
1389
  }
1390

    
1391
  @Override
1392
  public DynField setDefaultFieldValue(Object defaultValue) {
1393
    throw new UnsupportedOperationException();
1394
  }
1395

    
1396
  @Override
1397
  public DynField setClassOfItems(Class theClass) {
1398
    throw new UnsupportedOperationException();
1399
  }
1400

    
1401
  @Override
1402
  public DynField setType(DataType type) {
1403
    throw new UnsupportedOperationException();
1404
  }
1405

    
1406
  @Override
1407
  public DynField setSubtype(String subtype) {
1408
    throw new UnsupportedOperationException();
1409
  }
1410

    
1411
  @Override
1412
  public boolean isTime() {
1413
    return isTime;
1414
  }
1415

    
1416
  @Override
1417
  public FeatureAttributeGetter getFeatureAttributeGetter() {
1418
    return featureAttributeGetter;
1419
  }
1420

    
1421
  @Override
1422
  public void setFeatureAttributeGetter(
1423
          FeatureAttributeGetter featureAttributeTransform) {
1424
    this.featureAttributeGetter = featureAttributeTransform;
1425
  }
1426

    
1427
  @Override
1428
  public FeatureAttributeEmulator getFeatureAttributeEmulator() {
1429
    return this.featureAttributeEmulator;
1430
  }
1431

    
1432
  public FeatureAttributeDescriptor setFeatureAttributeEmulator(FeatureAttributeEmulator featureAttributeEmulator) {
1433
    this.featureAttributeEmulator = featureAttributeEmulator;
1434
    return this;
1435
  }
1436

    
1437
  @Override
1438
  public boolean isIndexed() {
1439
    return this.indexed;
1440
  }
1441

    
1442
  @Override
1443
  public boolean isForeingKey() {
1444
    return this.foreingKey != null && this.foreingKey.isForeingKey();
1445
  }
1446

    
1447
  @Override
1448
  public ForeingKey getForeingKey() {
1449
    return this.foreingKey;
1450
  }
1451

    
1452
  @Override
1453
  public boolean allowIndexDuplicateds() {
1454
    return this.allowIndexDuplicateds;
1455
  }
1456

    
1457
  @Override
1458
  public boolean isIndexAscending() {
1459
    return this.isIndexAscending;
1460
  }
1461

    
1462
  @Override
1463
  public DynField setClassOfValue(DynStruct dynStrct) {
1464
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1465
  }
1466

    
1467
  @Override
1468
  public DynField setClassOfValue(String theClassNameOfValue) {
1469
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1470
  }
1471

    
1472
  @Override
1473
  public String getClassNameOfValue() {
1474
    return null;
1475
  }
1476

    
1477
  @Override
1478
  public DynStruct getDynClassOfValue() {
1479
    return null;
1480
  }
1481

    
1482
  @Override
1483
  public DynField setTypeOfItems(int type) {
1484
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1485
  }
1486

    
1487
  @Override
1488
  public int getTypeOfItems() {
1489
    return DataTypes.INVALID;
1490
  }
1491

    
1492
  @Override
1493
  public DynField setClassOfItems(DynStruct dynStrct) {
1494
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1495
  }
1496

    
1497
  @Override
1498
  public DynField setClassOfItems(String theClassNameOfValue) {
1499
    throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
1500
  }
1501

    
1502
  @Override
1503
  public String getClassNameOfItems() {
1504
    return null;
1505
  }
1506

    
1507
  @Override
1508
  public DynStruct getDynClassOfItems() {
1509
    return null;
1510
  }
1511

    
1512
  @Override
1513
  public DynField setRelationType(int relationType) {
1514
    this.relationType = relationType;
1515
    return this;
1516
  }
1517

    
1518
  @Override
1519
  public int getRelationType() {
1520
    return this.relationType;
1521
  }
1522

    
1523
  @Override
1524
  public DynField setAvailableValues(DynMethod availableValuesMethod) {
1525
    this.availableValuesMethod = availableValuesMethod;
1526
    return this;
1527
  }
1528

    
1529
  @Override
1530
  public DynObjectValueItem[] getAvailableValues(DynObject self) {
1531
    if (this.availableValuesMethod != null) {
1532
      DynObjectValueItem[] values;
1533
      try {
1534
        values = (DynObjectValueItem[]) this.availableValuesMethod.invoke(self, new Object[]{this});
1535
      } catch (DynMethodException ex) {
1536
        return this.availableValues;
1537
      }
1538
      if (values != null) {
1539
        return values;
1540
      }
1541
    }
1542
    return this.availableValues;
1543
  }
1544

    
1545
  @Override
1546
  public DynMethod getAvailableValuesMethod() {
1547
    return this.availableValuesMethod;
1548
  }
1549

    
1550
  @Override
1551
  public boolean isAvailableValuesCalculated() {
1552
    return this.availableValuesMethod != null;
1553
  }
1554

    
1555
  @Override
1556
  public DynMethod getCalculateMethod() {
1557
    return this.calculateMethod;
1558
  }
1559

    
1560
  @Override
1561
  public DynField setCalculateMethod(DynMethod method) {
1562
    this.calculateMethod = method;
1563
    return this;
1564
  }
1565

    
1566
  @Override
1567
  public boolean isCalculated() {
1568
    return this.calculateMethod != null;
1569
  }
1570

    
1571
  @Override
1572
  public Object getCalculatedValue(DynObject self) {
1573
    try {
1574
      return this.calculateMethod.invoke(self, new Object[]{this});
1575
    } catch (DynMethodException ex) {
1576
      throw new RuntimeException(ex);
1577
    }
1578
  }
1579

    
1580
  @Override
1581
  public DynField setValidateElements(boolean validate) {
1582
    return this;
1583
  }
1584

    
1585
  @Override
1586
  public boolean getValidateElements() {
1587
    return false;
1588
  }
1589

    
1590
  @Override
1591
  public boolean hasLabel() {
1592
    return StringUtils.isNotBlank(this.label);
1593
  }
1594

    
1595
  @Override
1596
  public boolean hasShortLabel() {
1597
    return StringUtils.isNotBlank(this.shortLabel);
1598
  }
1599

    
1600
  @Override
1601
  public boolean hasDescription() {
1602
    return StringUtils.isNotBlank(this.description);
1603
  }
1604

    
1605
  @Override
1606
  public FeatureAttributeDescriptor getValue() {
1607
    return this;
1608
  }
1609

    
1610
  @Override
1611
  public int getDisplaySize() {
1612
    return this.displaySize;
1613
  }
1614

    
1615
  private class ConstantValueEvaluator extends AbstractEvaluator {
1616

    
1617
    @Override
1618
    public Object evaluate(EvaluatorData data) throws EvaluatorException {
1619
      return defaultValue;
1620
    }
1621

    
1622
    @Override
1623
    public String getName() {
1624
      return "Constant attribute " + name;
1625
    }
1626
  }
1627

    
1628
  public void setConstantValue(boolean isConstantValue) {
1629
    if (isConstantValue) {
1630
      /* Cuando un attributo tiene asociado un evaluador, este se interpreta
1631
             * como que no debe cargarse de la fuente de datos subyacente, siendo
1632
             * el evaluador el que se encarga de proporcionar su valor.
1633
             * Nos limitamos a asignar un evaluador que retorna simpre el valor
1634
             * por defecto para ese attributo.
1635
       */
1636
      this.evaluator = new ConstantValueEvaluator();
1637
    } else {
1638
      this.evaluator = null;
1639
    }
1640
  }
1641

    
1642
  @Override
1643
  public boolean isComputed() {
1644
    return featureAttributeEmulator != null || evaluator != null || isCalculated();
1645
  }
1646

    
1647
  @Override
1648
  public FeatureStore getStore() {
1649
    FeatureType ftype = this.getFeatureType();
1650
    if (ftype == null) {
1651
      return null;
1652
    }
1653
    return ftype.getStore();
1654
  }
1655

    
1656
  @Override
1657
  public FeatureType getFeatureType() {
1658
    if (this.typeRef == null) {
1659
      return null;
1660
    }
1661
    FeatureType ftype = (FeatureType) this.typeRef.get();
1662
//        LOGGER.info(String.format("FeatureAttributeDescriptor[%08x] get FeatureType [%08x], ref [%08x].", this.hashCode(), ftype.hashCode(), typeRef.hashCode()));
1663
    return ftype;
1664
  }
1665

    
1666
  public FeatureAttributeDescriptor setInterval(Interval interval) {
1667
    this.interval = interval;
1668
    return this;
1669
  }
1670

    
1671
  public void fixAll() {
1672
    if (!this.getDataType().supportSize()) {
1673
      this.size = 0;
1674
    }
1675
    NumberPrecisionAndScale ps = this.getDataType().fixPrecisionAndScale(this.precision, this.scale);
1676
    this.precision = ps.getPrecision();
1677
    this.scale = ps.getScale();
1678

    
1679
    switch (this.getType()) {
1680
      case DataTypes.INSTANT:
1681
      case DataTypes.INTERVAL:
1682
      case DataTypes.DATE:
1683
      case DataTypes.TIME:
1684
      case DataTypes.TIMESTAMP:
1685
        if (this.getInterval() != null) {
1686
          this.isTime = true;
1687
        }
1688
        break;
1689
    }
1690
  }
1691

    
1692
  @Override
1693
  public String[] getRequiredFieldNames() {
1694
    FeatureAttributeEmulator emulator = this.getFeatureAttributeEmulator();
1695
    if (emulator == null) {
1696
      return null;
1697
    }
1698
    return emulator.getRequiredFieldNames();
1699
  }
1700

    
1701
  @Override
1702
  public void recentUsed() {
1703
    DefaultFeatureType.RECENTS_USEDS.add(this);
1704
  }
1705

    
1706
  @Override
1707
  public boolean hasOnlyMetadataChanges(FeatureAttributeDescriptor other) {
1708
    if (other == null) {
1709
      throw new NullPointerException();
1710
    }
1711
    DefaultFeatureAttributeDescriptor old = (DefaultFeatureAttributeDescriptor) other;
1712
    if (!StringUtils.equalsIgnoreCase(old.name, this.name)) {
1713
      return false;
1714
    }
1715
    if (old.isComputed() && old.isComputed() == this.isComputed()) {
1716
      return true;
1717
    }
1718
    if (this.dataType != old.dataType) {
1719
      return false;
1720
    }
1721
    if (this.size != old.size) {
1722
      return false;
1723
    }
1724
    if (this.precision != old.precision) {
1725
      return false;
1726
    }
1727
//        if( this.primaryKey != old.primaryKey ) {
1728
//            return false;
1729
//        }
1730
    if (this.geomType != old.geomType) {
1731
      return false;
1732
    }
1733
    if (this.SRS != old.SRS) {
1734
      return false;
1735
    }
1736
    if (this.isAutomatic != old.isAutomatic) {
1737
      return false;
1738
    }
1739
    return true;
1740
  }
1741

    
1742
  private String getAll() {
1743
    StringBuilder builder = new StringBuilder();
1744
    builder.append(this.name).append("__");
1745
    builder.append(this.dataType.getName());
1746
    if( this.size>0 ) {
1747
        builder.append("__set__size=").append(this.size);
1748
    }
1749
    if( this.precision>0 ) {
1750
        builder.append("__set__precision=").append(this.precision);
1751
    }
1752
    if( this.isHidden() ) { 
1753
        builder.append("__set__hidden=true");
1754
    }
1755
    if( this.isReadOnly() ) {
1756
        builder.append("__set__readonly=true");
1757
    }
1758
    builder.append("__set__allownull=").append(this.allowNull());
1759
    if( this.isPrimaryKey()) { 
1760
        builder.append("__set__pk=true");
1761
    }
1762
    if( this.isAutomatic()) { 
1763
        builder.append("__set__automatic=true");
1764
    }
1765
    if( this.isTime()) { 
1766
        builder.append("__set__istime=true");
1767
    }
1768
    if( !StringUtils.isBlank(this.getDataProfileName()) ) {
1769
        builder.append("__set__profile=").append(this.getDataProfileName());
1770
    }
1771
    if( !StringUtils.isBlank(this.getGroup()) ) {
1772
        builder.append("__set__group=").append(this.getGroup());
1773
    }
1774
    if( !StringUtils.isBlank(this.description) ) {
1775
        builder.append("__set__description=").append(this.description);
1776
    }
1777
    if( !StringUtils.isBlank(this.label) ) {
1778
        builder.append("__set__label=").append(this.label);
1779
    }
1780
    if( !StringUtils.isBlank(this.shortLabel) ) {
1781
        builder.append("__set__shortLabel=").append(this.shortLabel);
1782
    }
1783
    if( this.locale!=null ) {
1784
        builder.append("__set__locale=").append(this.getLocale());
1785
    }
1786
    builder.append("__set__order=").append(this.getOder());
1787
    if( this.getSRS()!=null ) {
1788
        builder.append("__set__srs=").append(this.getSRS().getAbrev());
1789
    }
1790
    if( this.getGeomType()!=null ) {
1791
        builder.append("__set__geomtype=").append(this.getGeomType().getFullName().replace(":", "@"));
1792
    }
1793
    return builder.toString();
1794
  }
1795
  
1796
  @Override
1797
  public Object get(String name) {
1798
    if (StringUtils.isBlank(name)) {
1799
      throw new IllegalArgumentException("Name can't be empty");
1800
    }
1801
    switch (name.trim().toLowerCase()) {
1802
      case "all":
1803
          return this.getAll();
1804
      case "isreadonly":
1805
      case "readonly":
1806
        return this.isReadOnly();
1807
      case "hidden":
1808
        return this.isHidden();
1809
      case "allownull":
1810
        return this.allowNull();
1811
      case "pk":
1812
      case "ispk":
1813
      case "primarykey":
1814
      case "isprimarykey":
1815
        return this.isPrimaryKey();
1816
      case "isautomatic":
1817
      case "automatic":
1818
        return this.isAutomatic();
1819
      case "time":
1820
      case "istime":
1821
        return this.isTime();
1822
      case "profile":
1823
        return this.getDataProfile();
1824
      case "group":
1825
        return this.getGroup();
1826
      case "description":
1827
        return this.getDescription();
1828
      case "label":
1829
        return this.getLabel();
1830
      case "shortlabel":
1831
        return this.getShortLabel();
1832
      case "expression":
1833
        return this.getFeatureAttributeEmulator();
1834
      case "size":
1835
        return this.getSize();
1836
      case "precision":
1837
        return this.getPrecision();
1838
      case "scale":
1839
        return this.getScale();
1840
      case "roundmode":
1841
        return this.getRoundMode();
1842
      case "locale":
1843
        return this.getLocale();
1844
      case "order":
1845
        return this.getOder();
1846
      case "foreingkey":
1847
        return this.getForeingKey();
1848
      case "interval":
1849
        return this.getInterval();
1850
      case "geomtype":
1851
      case "geometrytype":
1852
        return this.getGeomType();
1853
      case "srs":
1854
        return this.getSRS();
1855
      default:
1856
        throw new IllegalArgumentException("Name attribute '" + name + "' not valid.");
1857
    }
1858
  }
1859

    
1860
}