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 / DefaultFeature.java @ 45769

History | View | Annotate | Download (47.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
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl;
25

    
26
import java.lang.ref.WeakReference;
27
import java.math.BigDecimal;
28
import java.time.LocalDateTime;
29
import java.time.ZoneId;
30
import java.time.format.DateTimeFormatter;
31
import java.util.ArrayList;
32
import java.util.Date;
33
import java.util.HashMap;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Map;
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.cresques.cts.IProjection;
42
import org.gvsig.expressionevaluator.ExpressionUtils;
43
import org.gvsig.fmap.dal.DALLocator;
44
import org.gvsig.fmap.dal.DataTypes;
45
import org.gvsig.fmap.dal.exception.DataEvaluatorRuntimeException;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.feature.DataProfile;
48
import org.gvsig.fmap.dal.feature.EditableFeature;
49
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
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.FeatureExtraColumns;
55
import org.gvsig.fmap.dal.feature.FeatureReference;
56
import org.gvsig.fmap.dal.feature.FeatureStore;
57
import org.gvsig.fmap.dal.feature.FeatureType;
58
import org.gvsig.fmap.dal.feature.exception.IllegalValueException;
59
import org.gvsig.fmap.dal.feature.exception.SetReadOnlyAttributeException;
60
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
61
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
62
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
63
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
64
import org.gvsig.fmap.geom.Geometry;
65
import org.gvsig.fmap.geom.primitive.Envelope;
66
import org.gvsig.json.Json;
67
import org.gvsig.json.JsonObjectBuilder;
68
import org.gvsig.tools.ToolsLocator;
69
import org.gvsig.tools.dataTypes.Coercion;
70
import org.gvsig.tools.dataTypes.CoercionException;
71
import org.gvsig.tools.dataTypes.DataType;
72
import org.gvsig.tools.dataTypes.DataTypesManager;
73
import org.gvsig.tools.dataTypes.impl.coercion.CoerceToString;
74
import org.gvsig.tools.dynobject.DynObject;
75
import org.gvsig.tools.evaluator.Evaluator;
76
import org.gvsig.tools.evaluator.EvaluatorData;
77
import org.gvsig.tools.evaluator.EvaluatorException;
78
import org.gvsig.tools.exception.BaseException;
79
import org.gvsig.tools.exception.BaseRuntimeException;
80
import org.gvsig.tools.lang.Cloneable;
81
import org.slf4j.Logger;
82
import org.slf4j.LoggerFactory;
83

    
84
@SuppressWarnings("UseSpecificCatch")
85
public class DefaultFeature implements Feature, EvaluatorData, Cloneable {
86

    
87
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeature.class);
88

    
89
    private static DataTypesManager dataTypesManager = null;
90
    protected FeatureProvider data;
91
    protected FeatureReference reference;
92
    private WeakReference storeRef;
93

    
94
    private boolean inserted = false;
95
    private Object[] extraValuesData;
96
    private Map<String, Object> extraValues; // not persistent
97

    
98
    /*
99
         * Usar con mucha precaucion o mejor no usar. Lo precisa el
100
         * DefaultFeatureSet en la ordenacion.
101
     */
102
    public DefaultFeature(FeatureStore store) {
103
        this.storeRef = new WeakReference(store);
104
        this.reference = null;
105
    }
106

    
107
    public DefaultFeature(FeatureStore store, FeatureProvider data) {
108
        this.data = data;
109
        this.extraValuesData = null;
110
        this.storeRef = new WeakReference(store);
111
        this.reference = null;
112
        this.inserted = !data.isNew();
113
    }
114

    
115
    DefaultFeature(DefaultFeature feature) {
116
        this.data = feature.data.getCopy();
117
        this.extraValuesData = ArrayUtils.clone(feature.extraValuesData);
118
        this.storeRef = feature.storeRef;
119
        this.reference = feature.reference;
120
        this.inserted = feature.isInserted();
121
    }
122

    
123
    public DefaultFeature(FeatureType targetType, Feature sourceFeature) {
124
        DefaultFeature defaultFeature = (DefaultFeature) sourceFeature;
125
        this.data = new DefaultFeatureProvider(targetType, (DefaultFeatureProvider) defaultFeature.getData());
126
        this.extraValuesData = null;
127
        this.storeRef = defaultFeature.storeRef;
128
        this.reference = defaultFeature.reference;
129
        this.inserted = defaultFeature.isInserted();
130

    
131
        FeatureType sourceType = sourceFeature.getType();
132

    
133
        for (FeatureAttributeDescriptor targetAttrDescriptor : targetType) {
134
            if (targetAttrDescriptor.isComputed()) {
135
                continue;
136
            }
137
            int sourceIndex = sourceType.getIndex(targetAttrDescriptor.getName());
138
            if (sourceIndex < 0) {
139
                continue;
140
            }
141
            Object value = sourceFeature.get(sourceIndex);
142
            if (value == null && !targetAttrDescriptor.allowNull()) {
143
                continue;
144
            }
145
            this.setforced(targetAttrDescriptor.getIndex(), targetAttrDescriptor, value);
146
        }
147
    }
148

    
149
    public void setData(FeatureProvider data) {
150
        this.data = data;
151
        this.extraValuesData = null;
152
        this.reference = null;
153
        this.inserted = true;
154
    }
155

    
156
    public FeatureProvider getData() {
157
        return this.data;
158
    }
159

    
160
    protected DataTypesManager getDataTypesManager() {
161
        if (dataTypesManager == null) {
162
            dataTypesManager = ToolsLocator.getDataTypesManager();
163
        }
164
        return dataTypesManager;
165
    }
166

    
167
    protected void set(FeatureAttributeDescriptor attribute, Object value) {
168
        int i = attribute.getIndex();
169

    
170
        if( this.isInserted() ) {
171
            if (attribute.isReadOnly()) {
172
                throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
173
            }
174
        } else {
175
            if (attribute.isComputed()) {
176
                throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
177
            }
178
        }
179
        FeatureAttributeEmulator emulator = attribute.getFeatureAttributeEmulator();
180
        if (emulator != null) {
181
            emulator.set((EditableFeature) this, value);
182
            return;
183
        }
184

    
185
        if (value == null) {
186
            if (!attribute.allowNull()) {
187
                if (!attribute.isAutomatic()) {
188
                    throw new IllegalValueException(attribute, value);
189
                }
190
            }
191
            this.data.set(i, null);
192
            return;
193

    
194
        }
195

    
196
        if (attribute.getFeatureAttributeGetter() != null) {
197
            value = attribute.getFeatureAttributeGetter().setter(value);
198
        }
199
        this.setforced(i, attribute, value);
200
    }
201

    
202
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
203

    
204
        Class objectClass = attribute.getObjectClass();
205
        if (objectClass != null) {
206
            if (objectClass.isInstance(value)) {
207
                if (attribute.getType() == DataTypes.DECIMAL) {
208
                    BigDecimal d = (BigDecimal) value;
209
                    if (d.scale() == attribute.getScale() && d.precision() <= attribute.getPrecision()) {
210
                        this.data.set(i, value);
211
                        return;
212
                    }
213
                } else if (attribute.getType() == DataTypes.GEOMETRY) {
214
                    if (!attribute.getGeomType().equals(((Geometry) value).getGeometryType())) {
215
                        try {
216
                            Coercion coercer = attribute.getDataType().getCoercion();
217
                            value = coercer.coerce(value, attribute.getCoercionContext());
218
                        } catch (CoercionException e) {
219
                            throw new IllegalArgumentException("Can't convert to "
220
                                    + attribute.getDataType().getName()
221
                                    + " from '"
222
                                    + value == null ? "NULL" : value.getClass().getName()
223
                                            + "' with value '"
224
                                            + Objects.toString(value)
225
                                            + "' and context '"
226
                                            + attribute.getCoercionContext()
227
                                            + "'.");
228
                        }
229
                    } 
230
                    this.data.set(i, value);
231
                    return;
232
                } else {
233
                    this.data.set(i, value);
234
                    return;
235
                }
236
            }
237
            DataProfile dataProfile = attribute.getDataProfile();
238
            if (dataProfile != null) {
239
                try {
240
                    value = dataProfile.coerce(
241
                            attribute.getDataType(),
242
                            value,
243
                            attribute.getTags()
244
                    );
245
                } catch (CoercionException e) {
246

    
247
                }
248
            }
249
            try {
250
                Coercion coercer = attribute.getDataType().getCoercion();
251
                if (attribute.getType() == DataTypes.STRING && value instanceof Boolean) {
252
                    value = coercer.coerce(value, attribute.getCoercionContext());
253
                    value = StringUtils.left((String) value, attribute.getSize());
254
                } else {
255
                    value = coercer.coerce(value, attribute.getCoercionContext());
256
                }
257
            } catch (CoercionException e) {
258
                throw new IllegalArgumentException("Can't convert to "
259
                        + attribute.getDataType().getName()
260
                        + " from '"
261
                        + value == null ? "NULL" : value.getClass().getName()
262
                                + "' with value '"
263
                                + Objects.toString(value)
264
                                + "' and context '"
265
                                + attribute.getCoercionContext()
266
                                + "'.");
267
            }
268
        }
269
        this.data.set(i, value);
270
    }
271

    
272
    private Object get(int index, Class theClass, int type) {
273
        Object value = this.get(index);
274
        if (theClass.isInstance(value)) {
275
            return value;
276
        }
277
        try {
278
            return this.getDataTypesManager().coerce(type, value);
279
        } catch (CoercionException e) {
280

    
281
            if (value == null) {
282
                return null;
283
            }
284
            throw new IllegalArgumentException(
285
                    "Can't convert to " + theClass.getName()
286
                    + " from '" + value.getClass().getName()
287
                    + "' with value '" + value.toString() + "'.");
288
        }
289
    }
290

    
291
    public void initializeValues() {
292
        FeatureType type = this.getType();
293
        for (FeatureAttributeDescriptor attribute : type) {
294
            if (attribute.isAutomatic() || attribute.isReadOnly()
295
                    || attribute.isComputed()) {
296
                continue;
297
            }
298
            if (attribute.getDefaultValue() == null && !attribute.allowNull()) {
299
                continue;
300
            }
301
            Object value = attribute.getDefaultValue();
302
            if (value instanceof CharSequence) {
303
                String s = ((CharSequence) value).toString();
304
                if (ExpressionUtils.isDynamicText(s)) {
305
                    try {
306
                        value = ExpressionUtils.evaluateDynamicText(s);
307
                    } catch (Throwable th) {
308
                        value = null;
309
                    }
310
                }
311
            }
312
            this.set(attribute, value);
313
        }
314
    }
315

    
316
    public void clear() {
317
        initializeValues();
318
    }
319

    
320
    public void initializeValues(Feature feature) {
321
        FeatureType myType = this.getType();
322
        FeatureType type = feature.getType();
323
        extraValuesData = null;
324
        for (FeatureAttributeDescriptor attribute : type) {
325
            FeatureAttributeDescriptor myAttribute = myType.getAttributeDescriptor(attribute.getName());
326
            if (myAttribute != null) {
327
                this.set(myAttribute, feature.get(attribute.getIndex()));
328
            }
329
        }
330
    }
331

    
332
    @Override
333
    public FeatureStore getStore() {
334
        return (FeatureStore) this.storeRef.get();
335
    }
336

    
337
    @Override
338
    public FeatureType getType() {
339
        return this.data.getType();
340
    }
341

    
342
    @Override
343
    public EditableFeature getEditable() {
344
        return new DefaultEditableFeature(this);
345
    }
346

    
347
    @Override
348
    public Feature getCopy() {
349
        return new DefaultFeature(this);
350
    }
351

    
352
    @Override
353
    @SuppressWarnings("CloneDoesntCallSuperClone")
354
    public Object clone() throws CloneNotSupportedException {
355
        return new DefaultFeature(this);
356
    }
357

    
358
    @Override
359
    public FeatureReference getReference() {
360
        if (this.reference == null) {
361
            if (!isInserted()) {
362
                return null;
363
            }
364
            reference = FeatureReferenceFactory.createFromFeature(this);
365
        }
366
        return this.reference;
367
    }
368

    
369
    @Override
370
    public Object getOrDefault(String name, Object defaultValue) {
371
        int index = this.data.getType().getIndex(name);
372
        if (index < 0) {
373
            return defaultValue;
374
        }
375
        return this.get(index);
376
    }
377
    
378
    @Override
379
    public Object getOrDefault(String name, int type, Object defaultValue) {
380
        DataType dataType = ToolsLocator.getDataTypesManager().get(type);
381
        return getOrDefault(name, dataType, defaultValue);
382
    }
383
    
384
    @Override
385
    public Object getOrDefault(String name, DataType type, Object defaultValue) {
386
        int index = this.data.getType().getIndex(name);
387
        if (index < 0) {
388
            return defaultValue;
389
        }
390
        try {
391
            Object value = this.get(index);
392
            if(value == null){
393
                return defaultValue;
394
            }
395
            return type.coerce(value);
396
        } catch (Throwable th) {
397
            return defaultValue;
398
        }
399
    }
400

    
401
    @Override
402
    public String getStringOrDefault(String name, String defaultValue) {
403
        int index = this.data.getType().getIndex(name);
404
        if (index < 0) {
405
            return defaultValue;
406
        }
407
        try {
408
            return (String) this.get(index);
409
        } catch (Throwable th) {
410
            return defaultValue;
411
        }
412
    }
413

    
414
    @Override
415
    public boolean getBooleanOrDefault(String name, boolean defaultValue) {
416
        int index = this.data.getType().getIndex(name);
417
        if (index < 0) {
418
            return defaultValue;
419
        }
420
        try {
421
            return this.getBoolean(index);
422
        } catch (Throwable th) {
423
            return defaultValue;
424
        }
425
    }
426

    
427
    @Override
428
    public int getIntOrDefault(String name, int defaultValue) {
429
        int index = this.data.getType().getIndex(name);
430
        if (index < 0) {
431
            return defaultValue;
432
        }
433
        try {
434
            return this.getInt(index);
435
        } catch (Throwable th) {
436
            return defaultValue;
437
        }
438
    }
439

    
440
    @Override
441
    public long getLongOrDefault(String name, long defaultValue) {
442
        int index = this.data.getType().getIndex(name);
443
        if (index < 0) {
444
            return defaultValue;
445
        }
446
        try {
447
            return this.getLong(index);
448
        } catch (Throwable th) {
449
            return defaultValue;
450
        }
451
    }
452

    
453
    @Override
454
    public float getFloatOrDefault(String name, float defaultValue) {
455
        int index = this.data.getType().getIndex(name);
456
        if (index < 0) {
457
            return defaultValue;
458
        }
459
        try {
460
            return this.getFloat(index);
461
        } catch (Throwable th) {
462
            return defaultValue;
463
        }
464
    }
465

    
466
    @Override
467
    public double getDoubleOrDefault(String name, double defaultValue) {
468
        int index = this.data.getType().getIndex(name);
469
        if (index < 0) {
470
            return defaultValue;
471
        }
472
        try {
473
            return this.getDouble(index);
474
        } catch (Throwable th) {
475
            return defaultValue;
476
        }
477
    }
478

    
479
    @Override
480
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
481
        int index = this.data.getType().getIndex(name);
482
        if (index < 0) {
483
            return defaultValue;
484
        }
485
        try {
486
            return this.getDecimal(index);
487
        } catch (Throwable th) {
488
            return defaultValue;
489
        }
490
    }
491

    
492
    @Override
493
    public Date getDateOrDefault(String name, Date defaultValue) {
494
        int index = this.data.getType().getIndex(name);
495
        if (index < 0) {
496
            return defaultValue;
497
        }
498
        try {
499
            return this.getDate(index);
500
        } catch (Throwable th) {
501
            return defaultValue;
502
        }
503
    }
504

    
505
    @Override
506
    public Object getOrDefault(int index, Object defaultValue) {
507
        if (index < 0 || index >= this.data.getType().size()) {
508
            return defaultValue;
509
        }
510
        try {
511
            return this.get(index);
512
        } catch (Throwable th) {
513
            return defaultValue;
514
        }
515
    }
516

    
517
    @Override
518
    public String getStringOrDefault(int index, String defaultValue) {
519
        if (index < 0 || index >= this.data.getType().size()) {
520
            return defaultValue;
521
        }
522
        try {
523
            return this.getString(index);
524
        } catch (Throwable th) {
525
            return defaultValue;
526
        }
527
    }
528

    
529
    @Override
530
    public boolean getBooleanOrDefault(int index, boolean defaultValue) {
531
        if (index < 0 || index >= this.data.getType().size()) {
532
            return defaultValue;
533
        }
534
        try {
535
            return this.getBoolean(index);
536
        } catch (Throwable th) {
537
            return defaultValue;
538
        }
539
    }
540

    
541
    @Override
542
    public int getIntOrDefault(int index, int defaultValue) {
543
        if (index < 0 || index >= this.data.getType().size()) {
544
            return defaultValue;
545
        }
546
        try {
547
            return this.getInt(index);
548
        } catch (Throwable th) {
549
            return defaultValue;
550
        }
551
    }
552

    
553
    @Override
554
    public long getLongOrDefault(int index, long defaultValue) {
555
        if (index < 0 || index >= this.data.getType().size()) {
556
            return defaultValue;
557
        }
558
        try {
559
            return this.getLong(index);
560
        } catch (Throwable th) {
561
            return defaultValue;
562
        }
563
    }
564

    
565
    @Override
566
    public float getFloatOrDefault(int index, float defaultValue) {
567
        if (index < 0 || index >= this.data.getType().size()) {
568
            return defaultValue;
569
        }
570
        try {
571
            return this.getFloat(index);
572
        } catch (Throwable th) {
573
            return defaultValue;
574
        }
575
    }
576

    
577
    @Override
578
    public double getDoubleOrDefault(int index, double defaultValue) {
579
        if (index < 0 || index >= this.data.getType().size()) {
580
            return defaultValue;
581
        }
582
        try {
583
            return this.getDouble(index);
584
        } catch (Throwable th) {
585
            return defaultValue;
586
        }
587
    }
588

    
589
    @Override
590
    public BigDecimal getDecimalOrDefault(int index, BigDecimal defaultValue) {
591
        if (index < 0 || index >= this.data.getType().size()) {
592
            return defaultValue;
593
        }
594
        try {
595
            return this.getDecimal(index);
596
        } catch (Throwable th) {
597
            return defaultValue;
598
        }
599
    }
600

    
601
    @Override
602
    public Date getDateOrDefault(int index, Date defaultValue) {
603
        if (index < 0 || index >= this.data.getType().size()) {
604
            return defaultValue;
605
        }
606
        try {
607
            return this.getDate(index);
608
        } catch (Throwable th) {
609
            return defaultValue;
610
        }
611
    }
612

    
613
    @Override
614
    public void validate(int check) throws DataException {
615
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, check);
616
    }
617

    
618
    class UnableToGetReferenceException extends BaseRuntimeException {
619

    
620
        /**
621
         *
622
         */
623
        private static final long serialVersionUID = 1812805035204824163L;
624

    
625
        /**
626
         * @param exception
627
         */
628
        @SuppressWarnings("OverridableMethodCallInConstructor")
629
        public UnableToGetReferenceException(BaseException exception) {
630
            super("Unable to get reference", "_UnableToGetReferenceException",
631
                    serialVersionUID);
632
            this.initCause(exception);
633

    
634
        }
635

    
636
    }
637

    
638
    @Override
639
    public List getSRSs() {
640
        // TODO Auto-generated method stub
641
        return null;
642
    }
643

    
644
    @Override
645
    public Envelope getDefaultEnvelope() {
646
        Envelope envelope = this.data.getDefaultEnvelope();
647
        if (envelope == null) {
648
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
649
            if (i < 0) {
650
                return null;
651
            }
652
            Geometry geom = this.getDefaultGeometry();
653
            if (geom != null) {
654
                envelope = geom.getEnvelope();
655
            }
656
        }
657
        return envelope;
658
    }
659

    
660
    @Override
661
    public Geometry getDefaultGeometry() {
662
        Geometry geom = this.data.getDefaultGeometry();
663
        if (geom == null) {
664
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
665
            if (i < 0) {
666
                return null;
667
            }
668
            Object x = this.get(i);
669
            if (x instanceof Geometry) {
670
                geom = (Geometry) x;
671
            } else {
672
                geom = this.getGeometry(i);
673
            }
674
        }
675
        if (geom != null) {
676
            if (geom.getProjection() == null) {
677
                FeatureType type = this.getType();
678
                DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
679
                IProjection proj = attrdesc.getSRS(this.storeRef);
680
                geom.setProjection(proj);
681
            }
682
        }
683
        return geom;
684
    }
685

    
686
//    @Override
687
//    public Time getDefaultTime() {
688
//            Time time = this.data.getDefaultTime();
689
//        if( time == null ) {
690
//            int i = this.data.getType().getDefaultTimeAttributeIndex();
691
//            Object x = this.get(i);
692
//            if( x instanceof Time ) {
693
//                time = (Time) x;
694
//            } else {
695
//                time = this.getTime(i);
696
//            }
697
//        }
698
//        return time;
699
//    }
700
//
701
    @Override
702
    public IProjection getDefaultSRS() {
703
        IProjection srs = this.data.getType().getDefaultSRS();
704
        if (srs == null) {
705
            FeatureType type = this.getType();
706
            DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
707
            srs = attrdesc.getSRS(this.storeRef);
708
        }
709
        return srs;
710
    }
711

    
712
    @Override
713
    public List getGeometries() {
714
        // TODO Auto-generated method stub
715
        return null;
716
    }
717

    
718
    @Override
719
    public Object getFromProfile(int index) {
720
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
721
        Object value = this.get(index);
722
        String profileName = descriptor.getDataProfileName();
723
        if (StringUtils.isBlank(profileName)) {
724
            return value;
725
        }
726
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
727
        if (profile == null) {
728
            return value;
729
        }
730
        return profile.createData(value, descriptor.getTags());
731
    }
732

    
733
    @Override
734
    public Object getFromProfile(String name) {
735
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
736
        return this.getFromProfile(descriptor.getIndex());
737
    }
738

    
739
    @Override
740
    public Object get(String name) {
741
        int index = this.data.getType().getIndex(name);
742
        if (index < 0) {
743
            // buscamos en los extra cols
744
            if (hasExtraColumnValue(name)) {
745
                return getExtraColumnValue(name);
746
            }
747
            if (hasExtraValue(name)) {
748
                return getExtraValue(name);
749
            }
750
            // y si esta ahi return
751
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
752
        }
753
        return this.get(index);
754
    }
755

    
756
    @Override
757
    public boolean isNull(int index) {
758
        FeatureType type = this.data.getType();
759
        if (index < 0 || index >= type.size()) {
760
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
761
        }
762
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
763
        if (!this.data.getType().hasEvaluators()) {
764
            return this.data.get(index) == null;
765
        }
766
        Evaluator eval = attribute.getEvaluator();
767
        if (eval == null) {
768
            return this.data.get(index) == null;
769
        }
770
        Object value = this.data.get(index);
771
        if (value != null) {
772
            return true;
773
        }
774
        try {
775
            value = eval.evaluate(this);
776
        } catch (EvaluatorException e) {
777
            throw new DataEvaluatorRuntimeException(e);
778
        }
779
        this.data.set(index, value);
780
        return value == null;
781
    }
782

    
783
    @Override
784
    public boolean isNull(String name) {
785
        int index = this.data.getType().getIndex(name);
786
        if (index < 0) {
787
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
788
        }
789
        return this.isNull(index);
790
    }
791

    
792
    public boolean has_key(String key) {
793
        Object x = this.getType().get(key);
794
        return x != null;
795
    }
796

    
797
    public List<String> keys() {
798
        List<String> ks = new ArrayList<>();
799
        for (FeatureAttributeDescriptor attr : this.getType()) {
800
            ks.add(attr.getName());
801
        }
802
        return ks;
803
    }
804

    
805
    public Iterator<String> iterkeys() {
806
        final Iterator it = this.getType().iterator();
807
        return new Iterator<String>() {
808
            @Override
809
            public boolean hasNext() {
810
                return it.hasNext();
811
            }
812

    
813
            @Override
814
            public String next() {
815
                return ((FeatureAttributeDescriptor) it.next()).getName();
816
            }
817

    
818
            @Override
819
            public void remove() {
820
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
821
            }
822
        };
823
    }
824

    
825
    public Iterator iteritems() {
826
        final Iterator it = this.getType().iterator();
827
        return new Iterator<Map.Entry>() {
828
            @Override
829
            public boolean hasNext() {
830
                return it.hasNext();
831
            }
832

    
833
            @Override
834
            public Map.Entry next() {
835
                final String name = ((FeatureAttributeDescriptor) it.next()).getName();
836
                return new Map.Entry<String, Object>() {
837
                    @Override
838
                    public String getKey() {
839
                        return name;
840
                    }
841

    
842
                    @Override
843
                    public Object getValue() {
844
                        return get(name);
845
                    }
846

    
847
                    @Override
848
                    public Object setValue(Object value) {
849
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
850
                    }
851

    
852
                };
853
            }
854

    
855
            @Override
856
            public void remove() {
857
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
858
            }
859
        };
860
    }
861

    
862
    @Override
863
    public Object get(int index) {
864
        FeatureType type = this.data.getType();
865
        if (index < 0 || index >= type.size()) {
866
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
867
        }
868
        Object value = this.data.get(index);
869
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
870
        if (type.hasEvaluators()) {
871
            Evaluator eval = attribute.getEvaluator();
872
            if (eval != null) {
873
                if (value == null) { // Ya hemos calculado el campo ?
874
                    // FIXME: para comprobar si esta calculado usar un array especifico.
875
                    try {
876
                        value = eval.evaluate(this);
877
                    } catch (EvaluatorException e) {
878
                        throw new DataEvaluatorRuntimeException(e);
879
                    }
880
                    this.data.set(index, value);
881
                }
882
            }
883
        }
884
        value = get(attribute, value);
885
        return value;
886
    }
887

    
888
    private Object get(FeatureAttributeDescriptor featureAttributeDescriptor, Object value) {
889
        FeatureAttributeEmulator emulator = featureAttributeDescriptor.getFeatureAttributeEmulator();
890
        if (emulator != null) {
891
//            int index = featureAttributeDescriptor.getIndex();
892
//            value = this.data.get(index);
893
//            if( value==null ) {
894
            value = emulator.get(this);
895
//                this.data.set(index,value);
896
//            }
897
        } else {
898
            FeatureAttributeGetter getter = featureAttributeDescriptor.getFeatureAttributeGetter();
899
            if (getter != null) {
900
                value = getter.getter(value);
901
            }
902
        }
903
        DataType dataType = featureAttributeDescriptor.getDataType();
904
        Class<? extends DataType> theClass = dataType.getDefaultClass();
905
        if (theClass != null && !theClass.isInstance(value)) {
906
            try {
907
                value = this.getDataTypesManager().coerce(dataType.getType(), value);
908
            } catch (CoercionException e) {
909
                throw new IllegalArgumentException(
910
                        "Can't convert to " + theClass.getSimpleName()
911
                        + " from '" + value.getClass().getSimpleName()
912
                        + "' with value '" + value.toString() + "'.");
913
            }
914
        }
915
        if (featureAttributeDescriptor.getType() == DataTypes.GEOMETRY) {
916
            if (value != null) {
917
                Geometry geom = (Geometry) value;
918
                if (geom.getProjection() == null) {
919
                    IProjection proj = ((DefaultFeatureAttributeDescriptor) featureAttributeDescriptor).getSRS(this.storeRef);
920
                    geom.setProjection(proj);
921
                }
922
            }
923
        }
924
        return value;
925
    }
926

    
927
    @Override
928
    public byte[] getByteArray(String name) {
929
        return this.getByteArray(this.data.getType().getIndex(name));
930
    }
931

    
932
    @Override
933
    public byte[] getByteArray(int index) {
934
        return (byte[]) this.get(index);
935
    }
936

    
937
    @Override
938
    public Object[] getArray(String name) {
939
        return this.getArray(this.data.getType().getIndex(name));
940
    }
941

    
942
    @Override
943
    public Object[] getArray(int index) {
944
        return (Object[]) this.get(index);
945
    }
946

    
947
    @Override
948
    public boolean getBoolean(String name) {
949
        return this.getBoolean(this.data.getType().getIndex(name));
950
    }
951

    
952
    @Override
953
    public boolean getBoolean(int index) {
954
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
955
        if (value == null) {
956
            return false;
957
        }
958
        return value;
959
    }
960

    
961
    @Override
962
    public byte getByte(String name) {
963
        return this.getByte(this.data.getType().getIndex(name));
964
    }
965

    
966
    @Override
967
    public byte getByte(int index) {
968
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
969
        if (value == null) {
970
            return 0;
971
        }
972
        return value;
973
    }
974

    
975
    @Override
976
    public java.sql.Date getDate(String name) {
977
        return this.getDate(this.data.getType().getIndex(name));
978
    }
979

    
980
    @Override
981
    public java.sql.Date getDate(int index) {
982
        java.sql.Date value = ((java.sql.Date) this.get(index, java.sql.Date.class, DataTypes.DATE));
983
        return value;
984
    }
985

    
986
    @Override
987
    public java.sql.Time getTime(String name) {
988
        return this.getTime(this.data.getType().getIndex(name));
989
    }
990

    
991
    @Override
992
    public java.sql.Time getTime(int index) {
993
        java.sql.Time value = ((java.sql.Time) this.get(index, java.sql.Time.class, DataTypes.TIME));
994
        return value;
995
    }
996

    
997
    @Override
998
    public java.sql.Timestamp getTimestamp(String name) {
999
        return this.getTimestamp(this.data.getType().getIndex(name));
1000
    }
1001

    
1002
    @Override
1003
    public java.sql.Timestamp getTimestamp(int index) {
1004
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(index, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
1005
        return value;
1006
    }
1007

    
1008
    @Override
1009
    public double getDouble(String name) {
1010
        return this.getDouble(this.data.getType().getIndex(name));
1011
    }
1012

    
1013
    @Override
1014
    public double getDouble(int index) {
1015

    
1016
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
1017
        if (value == null) {
1018
            return 0;
1019
        }
1020
        return value;
1021
    }
1022

    
1023
    @Override
1024
    public BigDecimal getDecimal(String name) {
1025
        return this.getDecimal(this.data.getType().getIndex(name));
1026
    }
1027

    
1028
    @Override
1029
    public BigDecimal getDecimal(int index) {
1030
        BigDecimal value = ((BigDecimal) this.get(index, BigDecimal.class, DataTypes.DECIMAL));
1031
        return value;
1032
    }
1033

    
1034
    @Override
1035
    public Feature getFeature(String name) {
1036
        return this.getFeature(this.data.getType().getIndex(name));
1037
    }
1038

    
1039
    @Override
1040
    public Feature getFeature(int index) {
1041
        return (Feature) this.get(index);
1042
    }
1043

    
1044
    @Override
1045
    public float getFloat(String name) {
1046
        return this.getFloat(this.data.getType().getIndex(name));
1047
    }
1048

    
1049
    @Override
1050
    public float getFloat(int index) {
1051
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1052
        if (value == null) {
1053
            return 0;
1054
        }
1055
        return value;
1056
    }
1057

    
1058
    @Override
1059
    public Geometry getGeometry(String name) {
1060
        return this.getGeometry(this.data.getType().getIndex(name));
1061
    }
1062

    
1063
    @Override
1064
    public Geometry getGeometry(int index) {
1065
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1066
    }
1067

    
1068
    @Override
1069
    public int getInt(String name) {
1070
        return this.getInt(this.data.getType().getIndex(name));
1071
    }
1072

    
1073
    @Override
1074
    public int getInt(int index) {
1075
        Integer value = ((Integer) this.get(index, Integer.class, DataTypes.INT));
1076
        if (value == null) {
1077
            return 0;
1078
        }
1079
        return value;
1080
    }
1081

    
1082
    @Override
1083
    public long getLong(String name) {
1084
        return this.getLong(this.data.getType().getIndex(name));
1085
    }
1086

    
1087
    @Override
1088
    public long getLong(int index) {
1089
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1090
        if (value == null) {
1091
            return 0;
1092
        }
1093
        return value;
1094
    }
1095

    
1096
    @Override
1097
    public String getString(String name) {
1098
        return this.getString(this.data.getType().getIndex(name));
1099
    }
1100

    
1101
    @Override
1102
    public String getString(int index) {
1103
        return (String) this.get(index, String.class, DataTypes.STRING);
1104
    }
1105

    
1106
    @Override
1107
    public Object getContextValue(String name) {
1108
        name = name.toLowerCase();
1109
        if (name.equals("store")) {
1110
            return this.getStore();
1111
        }
1112

    
1113
        if (name.equals("featuretype")) {
1114
            return this.data.getType();
1115
        }
1116

    
1117
        if (name.equals("feature")) {
1118
            return this;
1119
        }
1120

    
1121
        throw new IllegalArgumentException(name);
1122
    }
1123

    
1124
    @Override
1125
    public Iterator getDataNames() {
1126
        class DataNamesIterator implements Iterator {
1127

    
1128
            Iterator attributeIteraror;
1129

    
1130
            DataNamesIterator(DefaultFeature feature) {
1131
                this.attributeIteraror = feature.getType().iterator();
1132
            }
1133

    
1134
            @Override
1135
            public boolean hasNext() {
1136
                return this.attributeIteraror.hasNext();
1137
            }
1138

    
1139
            @Override
1140
            public Object next() {
1141
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1142
                        .next()).getName();
1143
            }
1144

    
1145
            @Override
1146
            public void remove() {
1147
                throw new UnsupportedOperationException();
1148
            }
1149

    
1150
        }
1151
        return new DataNamesIterator(this);
1152
    }
1153

    
1154
    @Override
1155
    public Object getDataValue(String name) {
1156
        name = name.toLowerCase();
1157
        try {
1158
            return get(name);
1159
        } catch (IllegalArgumentException ex) {
1160
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1161
                return this.getDefaultGeometry();
1162
            }
1163
            throw ex;
1164
        }
1165
    }
1166

    
1167
    @Override
1168
    public Iterator getDataValues() {
1169
        class DataValuesIterator implements Iterator {
1170

    
1171
            DefaultFeature feature;
1172
            int current = 0;
1173

    
1174
            DataValuesIterator(DefaultFeature feature) {
1175
                this.feature = feature;
1176
            }
1177

    
1178
            @Override
1179
            public boolean hasNext() {
1180
                return current < feature.getType().size() - 1;
1181
            }
1182

    
1183
            @Override
1184
            public Object next() {
1185
                return feature.get(current++);
1186
            }
1187

    
1188
            @Override
1189
            public void remove() {
1190
                throw new UnsupportedOperationException();
1191
            }
1192

    
1193
        }
1194
        return new DataValuesIterator(this);
1195
    }
1196

    
1197
    @Override
1198
    public boolean hasContextValue(String name) {
1199
        name = name.toLowerCase();
1200
        if (name.equals("store")) {
1201
            return true;
1202
        }
1203

    
1204
        if (name.equals("featuretype")) {
1205
            return true;
1206
        }
1207

    
1208
        return name.equals("feature");
1209
    }
1210

    
1211
    @Override
1212
    public boolean hasDataValue(String name) {
1213
        return this.hasValue(name);
1214
    }
1215

    
1216
//    @Override
1217
//    public Time getTime(int index) {
1218
//        return ((Time) this.get(index,Time.class,DataTypes.INSTANT));
1219
//    }
1220
//
1221
//    @Override
1222
//    public Time getTime(String name) {
1223
//        return this.getInstant(this.data.getType().getIndex(name));
1224
//    }
1225
//
1226
//    @Override
1227
//    public Instant getInstant(int index) {
1228
//        return ((Instant) this.get(index,Instant.class,DataTypes.INSTANT));
1229
//    }
1230
//
1231
//    @Override
1232
//    public Instant getInstant(String name) {
1233
//        return this.getInstant(this.data.getType().getIndex(name));
1234
//    }
1235
//
1236
//    @Override
1237
//    public Interval getInterval(int index) {
1238
//        return ((Interval) this.get(index,Interval.class,DataTypes.INTERVAL));
1239
//    }
1240
//
1241
//    @Override
1242
//    public Interval getInterval(String name) {
1243
//        return this.getInterval(this.data.getType().getIndex(name));
1244
//    }
1245
//
1246
    @Override
1247
    public DynObject getAsDynObject() {
1248
        DynObjectFeatureFacade facade = new DynObjectFeatureFacade(this);
1249
        return facade;
1250
    }
1251

    
1252
    @Override
1253
    public String toString() {
1254
        StringBuilder builder = new StringBuilder();
1255
        FeatureAttributeDescriptor[] attributeDescriptors
1256
                = getType().getAttributeDescriptors();
1257
        for (int i = 0; i < attributeDescriptors.length; i++) {
1258
            String name = attributeDescriptors[i].getName();
1259
            Object value = get(name);
1260
            builder.append(value);
1261
            if (i < attributeDescriptors.length - 1) {
1262
                builder.append(", ");
1263
            }
1264
        }
1265
        return builder.toString();
1266
    }
1267

    
1268
    /**
1269
     * @return the inserted
1270
     */
1271
    public boolean isInserted() {
1272
        return inserted;
1273
    }
1274

    
1275
    /**
1276
     * @param inserted the inserted to set
1277
     */
1278
    public void setInserted(boolean inserted) {
1279
        this.inserted = inserted;
1280
//        this.data.setNew(!inserted);
1281
    }
1282

    
1283
    @Override
1284
    public EvaluatorData getEvaluatorData() {
1285
        return this;
1286
    }
1287

    
1288
    @Override
1289
    public int size() {
1290
        return this.data.getType().size();
1291
    }
1292

    
1293
    public boolean isEmpty() {
1294
        return false;
1295
    }
1296

    
1297
    public Iterator<String> iterator() {
1298
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1299
        return new Iterator<String>() {
1300
            @Override
1301
            public boolean hasNext() {
1302
                return x.hasNext();
1303
            }
1304

    
1305
            @Override
1306
            public String next() {
1307
                return x.next().getName();
1308
            }
1309
        };
1310
    }
1311

    
1312
    public boolean containsKey(String key) {
1313
        return this.data.getType().get(key) != null;
1314
    }
1315

    
1316
    @Override
1317
    public String getLabelOfValue(String name) {
1318
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1319
        if (attrdesc == null) {
1320
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1321
        }
1322
        Object value = this.get(attrdesc.getIndex());
1323
        String label = attrdesc.getLabelOfValue(value);
1324
        return label;
1325
    }
1326

    
1327
    @Override
1328
    public void setExtraValue(String name, Object value) {
1329
        if (this.extraValues == null) {
1330
            this.extraValues = new HashMap<>();
1331
        }
1332
        this.extraValues.put(name, value);
1333
    }
1334

    
1335
    public Object getExtraColumnValue(String name) {
1336
        Object value;
1337
        if (this.extraValues != null) {
1338
            if (this.extraValues.containsKey(name)) {
1339
                return this.extraValues.get(name);
1340
            }
1341
        }
1342
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1343
        int index = columns.getIndexOf(name);
1344
        if (index < 0) {
1345
            throw new RuntimeException("Not extra column value found");
1346
        }
1347
        if (extraValuesData == null) {
1348
            extraValuesData = new Object[columns.size()];
1349
        }
1350
        EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1351
        value = extraValuesData[index];
1352
        if (value != null) {
1353
            return value;
1354
        }
1355
        value = this.getExtraValue(name);
1356
        extraValuesData[index] = value;
1357
        if (value == null && !this.hasExtraValue(name)) {
1358
            if (attrdesc.getFeatureAttributeEmulator() != null) {
1359
                value = attrdesc.getFeatureAttributeEmulator().get(this);
1360
                extraValuesData[index] = value;
1361
            }
1362
        }
1363
        return value;
1364
    }
1365

    
1366
    @Override
1367
    public Object getExtraValue(String name) {
1368
        Object value = this.data.getExtraValue(name);
1369
        return value;
1370
    }
1371

    
1372
    @Override
1373
    public boolean hasExtraValue(String name) {
1374
        return this.data.hasExtraValue(name);
1375
    }
1376

    
1377
    private boolean hasExtraColumnValue(String name) {
1378
        if (this.extraValues != null) {
1379
            if (this.extraValues.containsKey(name)) {
1380
                return true;
1381
            }
1382
        }
1383
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1384
        int index = columns.getIndexOf(name);
1385
        if (index >= 0) {
1386
            return true;
1387
        }
1388
        return false;
1389
    }
1390

    
1391
    @Override
1392
    public boolean hasValue(String name) {
1393
        name = name.toLowerCase();
1394
        return this.data.getType().getIndex(name) >= 0
1395
                || hasExtraValue(name)
1396
                || hasExtraColumnValue(name);
1397
    }
1398

    
1399
    @Override
1400
    public Object getExtraValue(int index) {
1401
        return this.data.getExtraValue(index);
1402
    }
1403

    
1404
    @Override
1405
    public JsonObject toJson() {
1406
        JsonObjectBuilder builder = this.toJsonBuilder();
1407
        return builder.build();
1408
    }
1409

    
1410
    @Override
1411
    public JsonObjectBuilder toJsonBuilder() {
1412
        JsonObjectBuilder builder = Json.createObjectBuilder();
1413
        Date date;
1414
        Geometry geom;
1415
        FeatureType ft = this.getType();
1416
        for (FeatureAttributeDescriptor desc : ft) {
1417
            if (desc.isComputed()) {
1418
                continue;
1419
            }
1420
            if(this.isNull(desc.getName())){
1421
                builder.addNull(desc.getName());
1422
                continue;
1423
            }
1424
            switch (desc.getType()) {
1425
                case DataTypes.GEOMETRY:
1426
                    geom = this.getGeometry(desc.getIndex());
1427
                    if (geom != null) {
1428
                        builder.add(desc.getName(), geom.convertToHexWKBQuietly());
1429
                    }
1430
                    break;
1431
                case DataTypes.BOOLEAN:
1432
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1433
                    break;
1434
                case DataTypes.BYTE:
1435
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1436
                    break;
1437
                case DataTypes.INT:
1438
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1439
                    break;
1440
                case DataTypes.LONG:
1441
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1442
                    break;
1443
                case DataTypes.DOUBLE:
1444
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1445
                    break;
1446
                case DataTypes.FLOAT:
1447
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1448
                    break;
1449
                case DataTypes.DATE:
1450
                    // Format date as ISO 8601
1451
                    date = this.getDate(desc.getIndex());
1452
                    if (date == null) {
1453
                        builder.addNull(desc.getName());
1454
                    } else {
1455
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1456
                        String value = DateTimeFormatter.ISO_DATE.format(localDateTime);
1457
                        builder.add(desc.getName(), value);
1458
                    }
1459
                    break;
1460
                case DataTypes.TIMESTAMP:
1461
                    // Format date as ISO 8601
1462
                    date = this.getTimestamp(desc.getIndex());
1463
                    if (date == null) {
1464
                        builder.addNull(desc.getName());
1465
                    } else {
1466
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1467
                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1468
                        builder.add(desc.getName(), value);
1469
                    }
1470
                    break;
1471
                case DataTypes.TIME:
1472
                    // Format date as ISO 8601
1473
                    date = this.getTime(desc.getIndex());
1474
                    if (date == null) {
1475
                        builder.addNull(desc.getName());
1476
                    } else {
1477
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1478
                        String value = DateTimeFormatter.ISO_TIME.format(localDateTime);
1479
                        builder.add(desc.getName(), value);
1480
                    }
1481
                    break;
1482
                default:
1483
                    builder.add(desc.getName(), this.getStringOrDefault(desc.getIndex(), ""));
1484
            }
1485
        }
1486
        return builder;
1487
    }
1488

    
1489
    @Override
1490
    public List<String> getKeys() {
1491
        List<String> l = new ArrayList<>();
1492
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1493
            l.add(descriptor.getName());
1494
        }
1495
        return l;
1496
    }
1497

    
1498
}