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

History | View | Annotate | Download (47.3 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 (attribute.isReadOnly()) {
171
            throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
172
        }
173
        FeatureAttributeEmulator emulator = attribute.getFeatureAttributeEmulator();
174
        if (emulator != null) {
175
            emulator.set((EditableFeature) this, value);
176
            return;
177
        }
178

    
179
        if (value == null) {
180
            if (!attribute.allowNull()) {
181
                if (!attribute.isAutomatic()) {
182
                    throw new IllegalValueException(attribute, value);
183
                }
184
            }
185
            this.data.set(i, null);
186
            return;
187

    
188
        }
189

    
190
        if (attribute.getFeatureAttributeGetter() != null) {
191
            value = attribute.getFeatureAttributeGetter().setter(value);
192
        }
193
        this.setforced(i, attribute, value);
194
    }
195

    
196
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
197

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

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

    
266
    private Object get(int index, Class theClass, int type) {
267
        Object value = this.get(index);
268
        if (theClass.isInstance(value)) {
269
            return value;
270
        }
271
        try {
272
            return this.getDataTypesManager().coerce(type, value);
273
        } catch (CoercionException e) {
274

    
275
            if (value == null) {
276
                return null;
277
            }
278
            throw new IllegalArgumentException(
279
                    "Can't convert to " + theClass.getName()
280
                    + " from '" + value.getClass().getName()
281
                    + "' with value '" + value.toString() + "'.");
282
        }
283
    }
284

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

    
310
    public void clear() {
311
        initializeValues();
312
    }
313

    
314
    public void initializeValues(Feature feature) {
315
        FeatureType myType = this.getType();
316
        FeatureType type = feature.getType();
317
        extraValuesData = null;
318
        for (FeatureAttributeDescriptor attribute : type) {
319
            FeatureAttributeDescriptor myAttribute = myType.getAttributeDescriptor(attribute.getName());
320
            if (myAttribute != null) {
321
                this.set(myAttribute, feature.get(attribute.getIndex()));
322
            }
323
        }
324
    }
325

    
326
    @Override
327
    public FeatureStore getStore() {
328
        return (FeatureStore) this.storeRef.get();
329
    }
330

    
331
    @Override
332
    public FeatureType getType() {
333
        return this.data.getType();
334
    }
335

    
336
    @Override
337
    public EditableFeature getEditable() {
338
        return new DefaultEditableFeature(this);
339
    }
340

    
341
    @Override
342
    public Feature getCopy() {
343
        return new DefaultFeature(this);
344
    }
345

    
346
    @Override
347
    @SuppressWarnings("CloneDoesntCallSuperClone")
348
    public Object clone() throws CloneNotSupportedException {
349
        return new DefaultFeature(this);
350
    }
351

    
352
    @Override
353
    public FeatureReference getReference() {
354
        if (this.reference == null) {
355
            if (!isInserted()) {
356
                return null;
357
            }
358
            reference = FeatureReferenceFactory.createFromFeature(this);
359
        }
360
        return this.reference;
361
    }
362

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

    
395
    @Override
396
    public String getStringOrDefault(String name, String defaultValue) {
397
        int index = this.data.getType().getIndex(name);
398
        if (index < 0) {
399
            return defaultValue;
400
        }
401
        try {
402
            return (String) this.get(index);
403
        } catch (Throwable th) {
404
            return defaultValue;
405
        }
406
    }
407

    
408
    @Override
409
    public boolean getBooleanOrDefault(String name, boolean defaultValue) {
410
        int index = this.data.getType().getIndex(name);
411
        if (index < 0) {
412
            return defaultValue;
413
        }
414
        try {
415
            return this.getBoolean(index);
416
        } catch (Throwable th) {
417
            return defaultValue;
418
        }
419
    }
420

    
421
    @Override
422
    public int getIntOrDefault(String name, int defaultValue) {
423
        int index = this.data.getType().getIndex(name);
424
        if (index < 0) {
425
            return defaultValue;
426
        }
427
        try {
428
            return this.getInt(index);
429
        } catch (Throwable th) {
430
            return defaultValue;
431
        }
432
    }
433

    
434
    @Override
435
    public long getLongOrDefault(String name, long defaultValue) {
436
        int index = this.data.getType().getIndex(name);
437
        if (index < 0) {
438
            return defaultValue;
439
        }
440
        try {
441
            return this.getLong(index);
442
        } catch (Throwable th) {
443
            return defaultValue;
444
        }
445
    }
446

    
447
    @Override
448
    public float getFloatOrDefault(String name, float defaultValue) {
449
        int index = this.data.getType().getIndex(name);
450
        if (index < 0) {
451
            return defaultValue;
452
        }
453
        try {
454
            return this.getFloat(index);
455
        } catch (Throwable th) {
456
            return defaultValue;
457
        }
458
    }
459

    
460
    @Override
461
    public double getDoubleOrDefault(String name, double defaultValue) {
462
        int index = this.data.getType().getIndex(name);
463
        if (index < 0) {
464
            return defaultValue;
465
        }
466
        try {
467
            return this.getDouble(index);
468
        } catch (Throwable th) {
469
            return defaultValue;
470
        }
471
    }
472

    
473
    @Override
474
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
475
        int index = this.data.getType().getIndex(name);
476
        if (index < 0) {
477
            return defaultValue;
478
        }
479
        try {
480
            return this.getDecimal(index);
481
        } catch (Throwable th) {
482
            return defaultValue;
483
        }
484
    }
485

    
486
    @Override
487
    public Date getDateOrDefault(String name, Date defaultValue) {
488
        int index = this.data.getType().getIndex(name);
489
        if (index < 0) {
490
            return defaultValue;
491
        }
492
        try {
493
            return this.getDate(index);
494
        } catch (Throwable th) {
495
            return defaultValue;
496
        }
497
    }
498

    
499
    @Override
500
    public Object getOrDefault(int index, Object defaultValue) {
501
        if (index < 0 || index >= this.data.getType().size()) {
502
            return defaultValue;
503
        }
504
        try {
505
            return this.get(index);
506
        } catch (Throwable th) {
507
            return defaultValue;
508
        }
509
    }
510

    
511
    @Override
512
    public String getStringOrDefault(int index, String defaultValue) {
513
        if (index < 0 || index >= this.data.getType().size()) {
514
            return defaultValue;
515
        }
516
        try {
517
            return this.getString(index);
518
        } catch (Throwable th) {
519
            return defaultValue;
520
        }
521
    }
522

    
523
    @Override
524
    public boolean getBooleanOrDefault(int index, boolean defaultValue) {
525
        if (index < 0 || index >= this.data.getType().size()) {
526
            return defaultValue;
527
        }
528
        try {
529
            return this.getBoolean(index);
530
        } catch (Throwable th) {
531
            return defaultValue;
532
        }
533
    }
534

    
535
    @Override
536
    public int getIntOrDefault(int index, int defaultValue) {
537
        if (index < 0 || index >= this.data.getType().size()) {
538
            return defaultValue;
539
        }
540
        try {
541
            return this.getInt(index);
542
        } catch (Throwable th) {
543
            return defaultValue;
544
        }
545
    }
546

    
547
    @Override
548
    public long getLongOrDefault(int index, long defaultValue) {
549
        if (index < 0 || index >= this.data.getType().size()) {
550
            return defaultValue;
551
        }
552
        try {
553
            return this.getLong(index);
554
        } catch (Throwable th) {
555
            return defaultValue;
556
        }
557
    }
558

    
559
    @Override
560
    public float getFloatOrDefault(int index, float defaultValue) {
561
        if (index < 0 || index >= this.data.getType().size()) {
562
            return defaultValue;
563
        }
564
        try {
565
            return this.getFloat(index);
566
        } catch (Throwable th) {
567
            return defaultValue;
568
        }
569
    }
570

    
571
    @Override
572
    public double getDoubleOrDefault(int index, double defaultValue) {
573
        if (index < 0 || index >= this.data.getType().size()) {
574
            return defaultValue;
575
        }
576
        try {
577
            return this.getDouble(index);
578
        } catch (Throwable th) {
579
            return defaultValue;
580
        }
581
    }
582

    
583
    @Override
584
    public BigDecimal getDecimalOrDefault(int index, BigDecimal defaultValue) {
585
        if (index < 0 || index >= this.data.getType().size()) {
586
            return defaultValue;
587
        }
588
        try {
589
            return this.getDecimal(index);
590
        } catch (Throwable th) {
591
            return defaultValue;
592
        }
593
    }
594

    
595
    @Override
596
    public Date getDateOrDefault(int index, Date defaultValue) {
597
        if (index < 0 || index >= this.data.getType().size()) {
598
            return defaultValue;
599
        }
600
        try {
601
            return this.getDate(index);
602
        } catch (Throwable th) {
603
            return defaultValue;
604
        }
605
    }
606

    
607
    @Override
608
    public void validate(int check) throws DataException {
609
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, check);
610
    }
611

    
612
    class UnableToGetReferenceException extends BaseRuntimeException {
613

    
614
        /**
615
         *
616
         */
617
        private static final long serialVersionUID = 1812805035204824163L;
618

    
619
        /**
620
         * @param exception
621
         */
622
        @SuppressWarnings("OverridableMethodCallInConstructor")
623
        public UnableToGetReferenceException(BaseException exception) {
624
            super("Unable to get reference", "_UnableToGetReferenceException",
625
                    serialVersionUID);
626
            this.initCause(exception);
627

    
628
        }
629

    
630
    }
631

    
632
    @Override
633
    public List getSRSs() {
634
        // TODO Auto-generated method stub
635
        return null;
636
    }
637

    
638
    @Override
639
    public Envelope getDefaultEnvelope() {
640
        Envelope envelope = this.data.getDefaultEnvelope();
641
        if (envelope == null) {
642
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
643
            if (i < 0) {
644
                return null;
645
            }
646
            Geometry geom = this.getDefaultGeometry();
647
            if (geom != null) {
648
                envelope = geom.getEnvelope();
649
            }
650
        }
651
        return envelope;
652
    }
653

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

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

    
706
    @Override
707
    public List getGeometries() {
708
        // TODO Auto-generated method stub
709
        return null;
710
    }
711

    
712
    @Override
713
    public Object getFromProfile(int index) {
714
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
715
        Object value = this.get(index);
716
        String profileName = descriptor.getDataProfileName();
717
        if (StringUtils.isBlank(profileName)) {
718
            return value;
719
        }
720
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
721
        if (profile == null) {
722
            return value;
723
        }
724
        return profile.createData(value, descriptor.getTags());
725
    }
726

    
727
    @Override
728
    public Object getFromProfile(String name) {
729
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
730
        return this.getFromProfile(descriptor.getIndex());
731
    }
732

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

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

    
777
    @Override
778
    public boolean isNull(String name) {
779
        int index = this.data.getType().getIndex(name);
780
        if (index < 0) {
781
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
782
        }
783
        return this.isNull(index);
784
    }
785

    
786
    public boolean has_key(String key) {
787
        Object x = this.getType().get(key);
788
        return x != null;
789
    }
790

    
791
    public List<String> keys() {
792
        List<String> ks = new ArrayList<>();
793
        for (FeatureAttributeDescriptor attr : this.getType()) {
794
            ks.add(attr.getName());
795
        }
796
        return ks;
797
    }
798

    
799
    public Iterator<String> iterkeys() {
800
        final Iterator it = this.getType().iterator();
801
        return new Iterator<String>() {
802
            @Override
803
            public boolean hasNext() {
804
                return it.hasNext();
805
            }
806

    
807
            @Override
808
            public String next() {
809
                return ((FeatureAttributeDescriptor) it.next()).getName();
810
            }
811

    
812
            @Override
813
            public void remove() {
814
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
815
            }
816
        };
817
    }
818

    
819
    public Iterator iteritems() {
820
        final Iterator it = this.getType().iterator();
821
        return new Iterator<Map.Entry>() {
822
            @Override
823
            public boolean hasNext() {
824
                return it.hasNext();
825
            }
826

    
827
            @Override
828
            public Map.Entry next() {
829
                final String name = ((FeatureAttributeDescriptor) it.next()).getName();
830
                return new Map.Entry<String, Object>() {
831
                    @Override
832
                    public String getKey() {
833
                        return name;
834
                    }
835

    
836
                    @Override
837
                    public Object getValue() {
838
                        return get(name);
839
                    }
840

    
841
                    @Override
842
                    public Object setValue(Object value) {
843
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
844
                    }
845

    
846
                };
847
            }
848

    
849
            @Override
850
            public void remove() {
851
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
852
            }
853
        };
854
    }
855

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

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

    
921
    @Override
922
    public byte[] getByteArray(String name) {
923
        return this.getByteArray(this.data.getType().getIndex(name));
924
    }
925

    
926
    @Override
927
    public byte[] getByteArray(int index) {
928
        return (byte[]) this.get(index);
929
    }
930

    
931
    @Override
932
    public Object[] getArray(String name) {
933
        return this.getArray(this.data.getType().getIndex(name));
934
    }
935

    
936
    @Override
937
    public Object[] getArray(int index) {
938
        return (Object[]) this.get(index);
939
    }
940

    
941
    @Override
942
    public boolean getBoolean(String name) {
943
        return this.getBoolean(this.data.getType().getIndex(name));
944
    }
945

    
946
    @Override
947
    public boolean getBoolean(int index) {
948
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
949
        if (value == null) {
950
            return false;
951
        }
952
        return value;
953
    }
954

    
955
    @Override
956
    public byte getByte(String name) {
957
        return this.getByte(this.data.getType().getIndex(name));
958
    }
959

    
960
    @Override
961
    public byte getByte(int index) {
962
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
963
        if (value == null) {
964
            return 0;
965
        }
966
        return value;
967
    }
968

    
969
    @Override
970
    public java.sql.Date getDate(String name) {
971
        return this.getDate(this.data.getType().getIndex(name));
972
    }
973

    
974
    @Override
975
    public java.sql.Date getDate(int index) {
976
        java.sql.Date value = ((java.sql.Date) this.get(index, java.sql.Date.class, DataTypes.DATE));
977
        return value;
978
    }
979

    
980
    @Override
981
    public java.sql.Time getTime(String name) {
982
        return this.getTime(this.data.getType().getIndex(name));
983
    }
984

    
985
    @Override
986
    public java.sql.Time getTime(int index) {
987
        java.sql.Time value = ((java.sql.Time) this.get(index, java.sql.Time.class, DataTypes.TIME));
988
        return value;
989
    }
990

    
991
    @Override
992
    public java.sql.Timestamp getTimestamp(String name) {
993
        return this.getTimestamp(this.data.getType().getIndex(name));
994
    }
995

    
996
    @Override
997
    public java.sql.Timestamp getTimestamp(int index) {
998
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(index, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
999
        return value;
1000
    }
1001

    
1002
    @Override
1003
    public double getDouble(String name) {
1004
        return this.getDouble(this.data.getType().getIndex(name));
1005
    }
1006

    
1007
    @Override
1008
    public double getDouble(int index) {
1009

    
1010
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
1011
        if (value == null) {
1012
            return 0;
1013
        }
1014
        return value;
1015
    }
1016

    
1017
    @Override
1018
    public BigDecimal getDecimal(String name) {
1019
        return this.getDecimal(this.data.getType().getIndex(name));
1020
    }
1021

    
1022
    @Override
1023
    public BigDecimal getDecimal(int index) {
1024
        BigDecimal value = ((BigDecimal) this.get(index, BigDecimal.class, DataTypes.DECIMAL));
1025
        return value;
1026
    }
1027

    
1028
    @Override
1029
    public Feature getFeature(String name) {
1030
        return this.getFeature(this.data.getType().getIndex(name));
1031
    }
1032

    
1033
    @Override
1034
    public Feature getFeature(int index) {
1035
        return (Feature) this.get(index);
1036
    }
1037

    
1038
    @Override
1039
    public float getFloat(String name) {
1040
        return this.getFloat(this.data.getType().getIndex(name));
1041
    }
1042

    
1043
    @Override
1044
    public float getFloat(int index) {
1045
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1046
        if (value == null) {
1047
            return 0;
1048
        }
1049
        return value;
1050
    }
1051

    
1052
    @Override
1053
    public Geometry getGeometry(String name) {
1054
        return this.getGeometry(this.data.getType().getIndex(name));
1055
    }
1056

    
1057
    @Override
1058
    public Geometry getGeometry(int index) {
1059
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1060
    }
1061

    
1062
    @Override
1063
    public int getInt(String name) {
1064
        return this.getInt(this.data.getType().getIndex(name));
1065
    }
1066

    
1067
    @Override
1068
    public int getInt(int index) {
1069
        Integer value = ((Integer) this.get(index, Integer.class, DataTypes.INT));
1070
        if (value == null) {
1071
            return 0;
1072
        }
1073
        return value;
1074
    }
1075

    
1076
    @Override
1077
    public long getLong(String name) {
1078
        return this.getLong(this.data.getType().getIndex(name));
1079
    }
1080

    
1081
    @Override
1082
    public long getLong(int index) {
1083
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1084
        if (value == null) {
1085
            return 0;
1086
        }
1087
        return value;
1088
    }
1089

    
1090
    @Override
1091
    public String getString(String name) {
1092
        return this.getString(this.data.getType().getIndex(name));
1093
    }
1094

    
1095
    @Override
1096
    public String getString(int index) {
1097
        return (String) this.get(index, String.class, DataTypes.STRING);
1098
    }
1099

    
1100
    @Override
1101
    public Object getContextValue(String name) {
1102
        name = name.toLowerCase();
1103
        if (name.equals("store")) {
1104
            return this.getStore();
1105
        }
1106

    
1107
        if (name.equals("featuretype")) {
1108
            return this.data.getType();
1109
        }
1110

    
1111
        if (name.equals("feature")) {
1112
            return this;
1113
        }
1114

    
1115
        throw new IllegalArgumentException(name);
1116
    }
1117

    
1118
    @Override
1119
    public Iterator getDataNames() {
1120
        class DataNamesIterator implements Iterator {
1121

    
1122
            Iterator attributeIteraror;
1123

    
1124
            DataNamesIterator(DefaultFeature feature) {
1125
                this.attributeIteraror = feature.getType().iterator();
1126
            }
1127

    
1128
            @Override
1129
            public boolean hasNext() {
1130
                return this.attributeIteraror.hasNext();
1131
            }
1132

    
1133
            @Override
1134
            public Object next() {
1135
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1136
                        .next()).getName();
1137
            }
1138

    
1139
            @Override
1140
            public void remove() {
1141
                throw new UnsupportedOperationException();
1142
            }
1143

    
1144
        }
1145
        return new DataNamesIterator(this);
1146
    }
1147

    
1148
    @Override
1149
    public Object getDataValue(String name) {
1150
        name = name.toLowerCase();
1151
        try {
1152
            return get(name);
1153
        } catch (IllegalArgumentException ex) {
1154
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1155
                return this.getDefaultGeometry();
1156
            }
1157
            throw ex;
1158
        }
1159
    }
1160

    
1161
    @Override
1162
    public Iterator getDataValues() {
1163
        class DataValuesIterator implements Iterator {
1164

    
1165
            DefaultFeature feature;
1166
            int current = 0;
1167

    
1168
            DataValuesIterator(DefaultFeature feature) {
1169
                this.feature = feature;
1170
            }
1171

    
1172
            @Override
1173
            public boolean hasNext() {
1174
                return current < feature.getType().size() - 1;
1175
            }
1176

    
1177
            @Override
1178
            public Object next() {
1179
                return feature.get(current++);
1180
            }
1181

    
1182
            @Override
1183
            public void remove() {
1184
                throw new UnsupportedOperationException();
1185
            }
1186

    
1187
        }
1188
        return new DataValuesIterator(this);
1189
    }
1190

    
1191
    @Override
1192
    public boolean hasContextValue(String name) {
1193
        name = name.toLowerCase();
1194
        if (name.equals("store")) {
1195
            return true;
1196
        }
1197

    
1198
        if (name.equals("featuretype")) {
1199
            return true;
1200
        }
1201

    
1202
        return name.equals("feature");
1203
    }
1204

    
1205
    @Override
1206
    public boolean hasDataValue(String name) {
1207
        return this.hasValue(name);
1208
    }
1209

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

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

    
1262
    /**
1263
     * @return the inserted
1264
     */
1265
    public boolean isInserted() {
1266
        return inserted;
1267
    }
1268

    
1269
    /**
1270
     * @param inserted the inserted to set
1271
     */
1272
    public void setInserted(boolean inserted) {
1273
        this.inserted = inserted;
1274
//        this.data.setNew(!inserted);
1275
    }
1276

    
1277
    @Override
1278
    public EvaluatorData getEvaluatorData() {
1279
        return this;
1280
    }
1281

    
1282
    @Override
1283
    public int size() {
1284
        return this.data.getType().size();
1285
    }
1286

    
1287
    public boolean isEmpty() {
1288
        return false;
1289
    }
1290

    
1291
    public Iterator<String> iterator() {
1292
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1293
        return new Iterator<String>() {
1294
            @Override
1295
            public boolean hasNext() {
1296
                return x.hasNext();
1297
            }
1298

    
1299
            @Override
1300
            public String next() {
1301
                return x.next().getName();
1302
            }
1303
        };
1304
    }
1305

    
1306
    public boolean containsKey(String key) {
1307
        return this.data.getType().get(key) != null;
1308
    }
1309

    
1310
    @Override
1311
    public String getLabelOfValue(String name) {
1312
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1313
        if (attrdesc == null) {
1314
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1315
        }
1316
        Object value = this.get(attrdesc.getIndex());
1317
        String label = attrdesc.getLabelOfValue(value);
1318
        return label;
1319
    }
1320

    
1321
    @Override
1322
    public void setExtraValue(String name, Object value) {
1323
        if (this.extraValues == null) {
1324
            this.extraValues = new HashMap<>();
1325
        }
1326
        this.extraValues.put(name, value);
1327
    }
1328

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

    
1360
    @Override
1361
    public Object getExtraValue(String name) {
1362
        Object value = this.data.getExtraValue(name);
1363
        return value;
1364
    }
1365

    
1366
    @Override
1367
    public boolean hasExtraValue(String name) {
1368
        return this.data.hasExtraValue(name);
1369
    }
1370

    
1371
    private boolean hasExtraColumnValue(String name) {
1372
        if (this.extraValues != null) {
1373
            if (this.extraValues.containsKey(name)) {
1374
                return true;
1375
            }
1376
        }
1377
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1378
        int index = columns.getIndexOf(name);
1379
        if (index >= 0) {
1380
            return true;
1381
        }
1382
        return false;
1383
    }
1384

    
1385
    @Override
1386
    public boolean hasValue(String name) {
1387
        name = name.toLowerCase();
1388
        return this.data.getType().getIndex(name) >= 0
1389
                || hasExtraValue(name)
1390
                || hasExtraColumnValue(name);
1391
    }
1392

    
1393
    @Override
1394
    public Object getExtraValue(int index) {
1395
        return this.data.getExtraValue(index);
1396
    }
1397

    
1398
    @Override
1399
    public JsonObject toJson() {
1400
        JsonObjectBuilder builder = this.toJsonBuilder();
1401
        return builder.build();
1402
    }
1403

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

    
1483
    @Override
1484
    public List<String> getKeys() {
1485
        List<String> l = new ArrayList<>();
1486
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1487
            l.add(descriptor.getName());
1488
        }
1489
        return l;
1490
    }
1491

    
1492
}