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

History | View | Annotate | Download (48.6 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.dynobject.DynObject;
74
import org.gvsig.tools.evaluator.Evaluator;
75
import org.gvsig.tools.evaluator.EvaluatorData;
76
import org.gvsig.tools.evaluator.EvaluatorException;
77
import org.gvsig.tools.exception.BaseException;
78
import org.gvsig.tools.exception.BaseRuntimeException;
79
import org.gvsig.tools.lang.Cloneable;
80
import org.slf4j.Logger;
81
import org.slf4j.LoggerFactory;
82

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

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

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

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

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

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

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

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

    
130
        FeatureType sourceType = sourceFeature.getType();
131

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

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

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

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

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

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

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

    
193
        }
194

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
617
    class UnableToGetReferenceException extends BaseRuntimeException {
618

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

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

    
633
        }
634

    
635
    }
636

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
851
                };
852
            }
853

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1120
        throw new IllegalArgumentException(name);
1121
    }
1122

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

    
1127
            Iterator attributeIteraror;
1128

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

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

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

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

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

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

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

    
1170
            DefaultFeature feature;
1171
            int current = 0;
1172

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

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

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

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

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

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

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

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

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

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

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

    
1267
    /**
1268
     * It is a new feature that has already been inserted into the store but has not yet been saved to disk
1269
     * 
1270
     * @return the inserted
1271
     */
1272
    public boolean isInserted() {
1273
        return inserted;
1274
    }
1275

    
1276
    /**
1277
     * If true, marks the feature as already inserted in the vault but has not yet been saved to disk
1278
     * 
1279
     * @param inserted the inserted to set
1280
     */
1281
    public void setInserted(boolean inserted) {
1282
        this.inserted = inserted;
1283
//        this.data.setNew(!inserted);
1284
    }
1285

    
1286
    @Override
1287
    public EvaluatorData getEvaluatorData() {
1288
        return this;
1289
    }
1290

    
1291
    @Override
1292
    public int size() {
1293
        return this.data.getType().size();
1294
    }
1295

    
1296
    public boolean isEmpty() {
1297
        return false;
1298
    }
1299

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

    
1308
            @Override
1309
            public String next() {
1310
                return x.next().getName();
1311
            }
1312
        };
1313
    }
1314

    
1315
    public boolean containsKey(String key) {
1316
        return this.data.getType().get(key) != null;
1317
    }
1318

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

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

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

    
1369
    @Override
1370
    public Object getExtraValue(String name) {
1371
        Object value = this.data.getExtraValue(name);
1372
        return value;
1373
    }
1374

    
1375
    @Override
1376
    public boolean hasExtraValue(String name) {
1377
        return this.data.hasExtraValue(name);
1378
    }
1379

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

    
1394
    private EditableFeatureAttributeDescriptor getExtraColumn(String name) {
1395
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1396
        return columns.get(name);
1397
    }
1398

    
1399
    @Override
1400
    public boolean hasValue(String name) {
1401
        name = name.toLowerCase();
1402
        return this.data.getType().getIndex(name) >= 0
1403
                || hasExtraValue(name)
1404
                || hasExtraColumnValue(name);
1405
    }
1406

    
1407
    @Override
1408
    public Object getExtraValue(int index) {
1409
        return this.data.getExtraValue(index);
1410
    }
1411

    
1412
    @Override
1413
    public JsonObject toJson() {
1414
        JsonObjectBuilder builder = this.toJsonBuilder();
1415
        return builder.build();
1416
    }
1417

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

    
1497
    @Override
1498
    public List<String> getKeys() {
1499
        List<String> l = new ArrayList<>();
1500
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1501
            l.add(descriptor.getName());
1502
        }
1503
        return l;
1504
    }
1505

    
1506
    @Override
1507
    public String format(String name) {
1508
        int index = this.data.getType().getIndex(name);
1509
        if (index < 0) {
1510
            // buscamos en los extra cols
1511
            FeatureAttributeDescriptor attribute = this.getExtraColumn(name);
1512
            if( attribute!=null ) {
1513
                Object value = getExtraColumnValue(name);
1514
                return attribute.format(value);
1515
            }
1516
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1517
        }
1518
        return this.format(index);
1519
    }
1520

    
1521
    @Override
1522
    public String format(int index) {
1523
        Object value = this.get(index);
1524
        FeatureType type = this.data.getType();
1525
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
1526
        return attribute.format(value);
1527
    }
1528

    
1529
    
1530
}