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

History | View | Annotate | Download (45.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 {
208
                    this.data.set(i, value);
209
                    return;
210
                }
211
            }
212
            DataProfile dataProfile = attribute.getDataProfile();
213
            if (dataProfile != null) {
214
                try {
215
                    value = dataProfile.coerce(
216
                            attribute.getDataType(),
217
                            value,
218
                            attribute.getTags()
219
                    );
220
                } catch (CoercionException e) {
221

    
222
                }
223
            }
224
            try {
225
                Coercion coercer = attribute.getDataType().getCoercion();
226
                if (attribute.getType() == DataTypes.STRING && value instanceof Boolean) {
227
                    value = coercer.coerce(value, attribute.getCoercionContext());
228
                    value = StringUtils.left((String) value, attribute.getSize());
229
                } else {
230
                    value = coercer.coerce(value, attribute.getCoercionContext());
231
                }
232
            } catch (CoercionException e) {
233
                throw new IllegalArgumentException("Can't convert to "
234
                        + attribute.getDataType().getName()
235
                        + " from '"
236
                        + value == null ? "NULL" : value.getClass().getName()
237
                                + "' with value '"
238
                                + Objects.toString(value)
239
                                + "' and context '"
240
                                + attribute.getCoercionContext()
241
                                + "'.");
242
            }
243
        }
244
        this.data.set(i, value);
245
    }
246

    
247
    private Object get(int index, Class theClass, int type) {
248
        Object value = this.get(index);
249
        if (theClass.isInstance(value)) {
250
            return value;
251
        }
252
        try {
253
            return this.getDataTypesManager().coerce(type, value);
254
        } catch (CoercionException e) {
255

    
256
            if (value == null) {
257
                return null;
258
            }
259
            throw new IllegalArgumentException(
260
                    "Can't convert to " + theClass.getName()
261
                    + " from '" + value.getClass().getName()
262
                    + "' with value '" + value.toString() + "'.");
263
        }
264
    }
265

    
266
    public void initializeValues() {
267
        FeatureType type = this.getType();
268
        for (FeatureAttributeDescriptor attribute : type) {
269
            if (attribute.isAutomatic() || attribute.isReadOnly()
270
                    || attribute.isComputed()) {
271
                continue;
272
            }
273
            if (attribute.getDefaultValue() == null && !attribute.allowNull()) {
274
                continue;
275
            }
276
            Object value = attribute.getDefaultValue();
277
            if (value instanceof CharSequence) {
278
                String s = ((CharSequence) value).toString();
279
                if (ExpressionUtils.isDynamicText(s)) {
280
                    try {
281
                        value = ExpressionUtils.evaluateDynamicText(s);
282
                    } catch (Throwable th) {
283
                        value = null;
284
                    }
285
                }
286
            }
287
            this.set(attribute, value);
288
        }
289
    }
290

    
291
    public void clear() {
292
        initializeValues();
293
    }
294

    
295
    public void initializeValues(Feature feature) {
296
        FeatureType myType = this.getType();
297
        FeatureType type = feature.getType();
298
        extraValuesData = null;
299
        for (FeatureAttributeDescriptor attribute : type) {
300
            FeatureAttributeDescriptor myAttribute = myType.getAttributeDescriptor(attribute.getName());
301
            if (myAttribute != null) {
302
                this.set(myAttribute, feature.get(attribute.getIndex()));
303
            }
304
        }
305
    }
306

    
307
    @Override
308
    public FeatureStore getStore() {
309
        return (FeatureStore) this.storeRef.get();
310
    }
311

    
312
    @Override
313
    public FeatureType getType() {
314
        return this.data.getType();
315
    }
316

    
317
    @Override
318
    public EditableFeature getEditable() {
319
        return new DefaultEditableFeature(this);
320
    }
321

    
322
    @Override
323
    public Feature getCopy() {
324
        return new DefaultFeature(this);
325
    }
326

    
327
    @Override
328
    @SuppressWarnings("CloneDoesntCallSuperClone")
329
    public Object clone() throws CloneNotSupportedException {
330
        return new DefaultFeature(this);
331
    }
332

    
333
    @Override
334
    public FeatureReference getReference() {
335
        if (this.reference == null) {
336
            if (!isInserted()) {
337
                return null;
338
            }
339
            reference = FeatureReferenceFactory.createFromFeature(this);
340
        }
341
        return this.reference;
342
    }
343

    
344
    @Override
345
    public Object getOrDefault(String name, Object defaultValue) {
346
        int index = this.data.getType().getIndex(name);
347
        if (index < 0) {
348
            return defaultValue;
349
        }
350
        return this.get(index);
351
    }
352

    
353
    @Override
354
    public String getStringOrDefault(String name, String defaultValue) {
355
        int index = this.data.getType().getIndex(name);
356
        if (index < 0) {
357
            return defaultValue;
358
        }
359
        try {
360
            return (String) this.get(index);
361
        } catch (Throwable th) {
362
            return defaultValue;
363
        }
364
    }
365

    
366
    @Override
367
    public boolean getBooleanOrDefault(String name, boolean defaultValue) {
368
        int index = this.data.getType().getIndex(name);
369
        if (index < 0) {
370
            return defaultValue;
371
        }
372
        try {
373
            return this.getBoolean(index);
374
        } catch (Throwable th) {
375
            return defaultValue;
376
        }
377
    }
378

    
379
    @Override
380
    public int getIntOrDefault(String name, int defaultValue) {
381
        int index = this.data.getType().getIndex(name);
382
        if (index < 0) {
383
            return defaultValue;
384
        }
385
        try {
386
            return this.getInt(index);
387
        } catch (Throwable th) {
388
            return defaultValue;
389
        }
390
    }
391

    
392
    @Override
393
    public long getLongOrDefault(String name, long defaultValue) {
394
        int index = this.data.getType().getIndex(name);
395
        if (index < 0) {
396
            return defaultValue;
397
        }
398
        try {
399
            return this.getLong(index);
400
        } catch (Throwable th) {
401
            return defaultValue;
402
        }
403
    }
404

    
405
    @Override
406
    public float getFloatOrDefault(String name, float defaultValue) {
407
        int index = this.data.getType().getIndex(name);
408
        if (index < 0) {
409
            return defaultValue;
410
        }
411
        try {
412
            return this.getFloat(index);
413
        } catch (Throwable th) {
414
            return defaultValue;
415
        }
416
    }
417

    
418
    @Override
419
    public double getDoubleOrDefault(String name, double defaultValue) {
420
        int index = this.data.getType().getIndex(name);
421
        if (index < 0) {
422
            return defaultValue;
423
        }
424
        try {
425
            return this.getDouble(index);
426
        } catch (Throwable th) {
427
            return defaultValue;
428
        }
429
    }
430

    
431
    @Override
432
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
433
        int index = this.data.getType().getIndex(name);
434
        if (index < 0) {
435
            return defaultValue;
436
        }
437
        try {
438
            return this.getDecimal(index);
439
        } catch (Throwable th) {
440
            return defaultValue;
441
        }
442
    }
443

    
444
    @Override
445
    public Date getDateOrDefault(String name, Date defaultValue) {
446
        int index = this.data.getType().getIndex(name);
447
        if (index < 0) {
448
            return defaultValue;
449
        }
450
        try {
451
            return this.getDate(index);
452
        } catch (Throwable th) {
453
            return defaultValue;
454
        }
455
    }
456

    
457
    @Override
458
    public Object getOrDefault(int index, Object defaultValue) {
459
        if (index < 0 || index >= this.data.getType().size()) {
460
            return defaultValue;
461
        }
462
        try {
463
            return this.get(index);
464
        } catch (Throwable th) {
465
            return defaultValue;
466
        }
467
    }
468

    
469
    @Override
470
    public String getStringOrDefault(int index, String defaultValue) {
471
        if (index < 0 || index >= this.data.getType().size()) {
472
            return defaultValue;
473
        }
474
        try {
475
            return this.getString(index);
476
        } catch (Throwable th) {
477
            return defaultValue;
478
        }
479
    }
480

    
481
    @Override
482
    public boolean getBooleanOrDefault(int index, boolean defaultValue) {
483
        if (index < 0 || index >= this.data.getType().size()) {
484
            return defaultValue;
485
        }
486
        try {
487
            return this.getBoolean(index);
488
        } catch (Throwable th) {
489
            return defaultValue;
490
        }
491
    }
492

    
493
    @Override
494
    public int getIntOrDefault(int index, int defaultValue) {
495
        if (index < 0 || index >= this.data.getType().size()) {
496
            return defaultValue;
497
        }
498
        try {
499
            return this.getInt(index);
500
        } catch (Throwable th) {
501
            return defaultValue;
502
        }
503
    }
504

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

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

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

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

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

    
565
    class UnableToGetReferenceException extends BaseRuntimeException {
566

    
567
        /**
568
         *
569
         */
570
        private static final long serialVersionUID = 1812805035204824163L;
571

    
572
        /**
573
         * @param exception
574
         */
575
        @SuppressWarnings("OverridableMethodCallInConstructor")
576
        public UnableToGetReferenceException(BaseException exception) {
577
            super("Unable to get reference", "_UnableToGetReferenceException",
578
                    serialVersionUID);
579
            this.initCause(exception);
580

    
581
        }
582

    
583
    }
584

    
585
    @Override
586
    public void validate(int mode) throws DataException {
587
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, mode);
588
    }
589

    
590
    @Override
591
    public List getSRSs() {
592
        // TODO Auto-generated method stub
593
        return null;
594
    }
595

    
596
    @Override
597
    public Envelope getDefaultEnvelope() {
598
        Envelope envelope = this.data.getDefaultEnvelope();
599
        if (envelope == null) {
600
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
601
            if (i < 0) {
602
                return null;
603
            }
604
            Geometry geom = this.getDefaultGeometry();
605
            if (geom != null) {
606
                envelope = geom.getEnvelope();
607
            }
608
        }
609
        return envelope;
610
    }
611

    
612
    @Override
613
    public Geometry getDefaultGeometry() {
614
        Geometry geom = this.data.getDefaultGeometry();
615
        if (geom == null) {
616
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
617
            if (i < 0) {
618
                return null;
619
            }
620
            Object x = this.get(i);
621
            if (x instanceof Geometry) {
622
                geom = (Geometry) x;
623
            } else {
624
                geom = this.getGeometry(i);
625
            }
626
        }
627
        if (geom != null) {
628
            if (geom.getProjection() == null) {
629
                FeatureType type = this.getType();
630
                DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
631
                IProjection proj = attrdesc.getSRS(this.storeRef);
632
                geom.setProjection(proj);
633
            }
634
        }
635
        return geom;
636
    }
637

    
638
//    @Override
639
//    public Time getDefaultTime() {
640
//            Time time = this.data.getDefaultTime();
641
//        if( time == null ) {
642
//            int i = this.data.getType().getDefaultTimeAttributeIndex();
643
//            Object x = this.get(i);
644
//            if( x instanceof Time ) {
645
//                time = (Time) x;
646
//            } else {
647
//                time = this.getTime(i);
648
//            }
649
//        }
650
//        return time;
651
//    }
652
//
653
    @Override
654
    public IProjection getDefaultSRS() {
655
        IProjection srs = this.data.getType().getDefaultSRS();
656
        if (srs == null) {
657
            FeatureType type = this.getType();
658
            DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
659
            srs = attrdesc.getSRS(this.storeRef);
660
        }
661
        return srs;
662
    }
663

    
664
    @Override
665
    public List getGeometries() {
666
        // TODO Auto-generated method stub
667
        return null;
668
    }
669

    
670
    @Override
671
    public Object getFromProfile(int index) {
672
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
673
        Object value = this.get(index);
674
        String profileName = descriptor.getDataProfileName();
675
        if (StringUtils.isBlank(profileName)) {
676
            return value;
677
        }
678
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
679
        if (profile == null) {
680
            return value;
681
        }
682
        return profile.createData(value, descriptor.getTags());
683
    }
684

    
685
    @Override
686
    public Object getFromProfile(String name) {
687
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
688
        return this.getFromProfile(descriptor.getIndex());
689
    }
690

    
691
    @Override
692
    public Object get(String name) {
693
        int index = this.data.getType().getIndex(name);
694
        if (index < 0) {
695
            // buscamos en los extra cols
696
            if (hasExtraColumnValue(name)) {
697
                return getExtraColumnValue(name);
698
            }
699
            if (hasExtraValue(name)) {
700
                return getExtraValue(name);
701
            }
702
            // y si esta ahi return
703
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
704
        }
705
        return this.get(index);
706
    }
707

    
708
    @Override
709
    public boolean isNull(int index) {
710
        FeatureType type = this.data.getType();
711
        if (index < 0 || index >= type.size()) {
712
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
713
        }
714
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
715
        if (!this.data.getType().hasEvaluators()) {
716
            return this.data.get(index) == null;
717
        }
718
        Evaluator eval = attribute.getEvaluator();
719
        if (eval == null) {
720
            return this.data.get(index) == null;
721
        }
722
        Object value = this.data.get(index);
723
        if (value != null) {
724
            return true;
725
        }
726
        try {
727
            value = eval.evaluate(this);
728
        } catch (EvaluatorException e) {
729
            throw new DataEvaluatorRuntimeException(e);
730
        }
731
        this.data.set(index, value);
732
        return value == null;
733
    }
734

    
735
    @Override
736
    public boolean isNull(String name) {
737
        int index = this.data.getType().getIndex(name);
738
        if (index < 0) {
739
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
740
        }
741
        return this.isNull(index);
742
    }
743

    
744
    public boolean has_key(String key) {
745
        Object x = this.getType().get(key);
746
        return x != null;
747
    }
748

    
749
    public List<String> keys() {
750
        List<String> ks = new ArrayList<>();
751
        for (FeatureAttributeDescriptor attr : this.getType()) {
752
            ks.add(attr.getName());
753
        }
754
        return ks;
755
    }
756

    
757
    public Iterator<String> iterkeys() {
758
        final Iterator it = this.getType().iterator();
759
        return new Iterator<String>() {
760
            @Override
761
            public boolean hasNext() {
762
                return it.hasNext();
763
            }
764

    
765
            @Override
766
            public String next() {
767
                return ((FeatureAttributeDescriptor) it.next()).getName();
768
            }
769

    
770
            @Override
771
            public void remove() {
772
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
773
            }
774
        };
775
    }
776

    
777
    public Iterator iteritems() {
778
        final Iterator it = this.getType().iterator();
779
        return new Iterator<Map.Entry>() {
780
            @Override
781
            public boolean hasNext() {
782
                return it.hasNext();
783
            }
784

    
785
            @Override
786
            public Map.Entry next() {
787
                final String name = ((FeatureAttributeDescriptor) it.next()).getName();
788
                return new Map.Entry<String, Object>() {
789
                    @Override
790
                    public String getKey() {
791
                        return name;
792
                    }
793

    
794
                    @Override
795
                    public Object getValue() {
796
                        return get(name);
797
                    }
798

    
799
                    @Override
800
                    public Object setValue(Object value) {
801
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
802
                    }
803

    
804
                };
805
            }
806

    
807
            @Override
808
            public void remove() {
809
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
810
            }
811
        };
812
    }
813

    
814
    @Override
815
    public Object get(int index) {
816
        FeatureType type = this.data.getType();
817
        if (index < 0 || index >= type.size()) {
818
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
819
        }
820
        Object value = this.data.get(index);
821
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
822
        if (type.hasEvaluators()) {
823
            Evaluator eval = attribute.getEvaluator();
824
            if (eval != null) {
825
                if (value == null) { // Ya hemos calculado el campo ?
826
                    // FIXME: para comprobar si esta calculado usar un array especifico.
827
                    try {
828
                        value = eval.evaluate(this);
829
                    } catch (EvaluatorException e) {
830
                        throw new DataEvaluatorRuntimeException(e);
831
                    }
832
                    this.data.set(index, value);
833
                }
834
            }
835
        }
836
        value = get(attribute, value);
837
        return value;
838
    }
839

    
840
    private Object get(FeatureAttributeDescriptor featureAttributeDescriptor, Object value) {
841
        FeatureAttributeEmulator emulator = featureAttributeDescriptor.getFeatureAttributeEmulator();
842
        if (emulator != null) {
843
//            int index = featureAttributeDescriptor.getIndex();
844
//            value = this.data.get(index);
845
//            if( value==null ) {
846
            value = emulator.get(this);
847
//                this.data.set(index,value);
848
//            }
849
        } else {
850
            FeatureAttributeGetter getter = featureAttributeDescriptor.getFeatureAttributeGetter();
851
            if (getter != null) {
852
                value = getter.getter(value);
853
            }
854
        }
855
        DataType dataType = featureAttributeDescriptor.getDataType();
856
        Class<? extends DataType> theClass = dataType.getDefaultClass();
857
        if (theClass != null && !theClass.isInstance(value)) {
858
            try {
859
                value = this.getDataTypesManager().coerce(dataType.getType(), value);
860
            } catch (CoercionException e) {
861
                throw new IllegalArgumentException(
862
                        "Can't convert to " + theClass.getSimpleName()
863
                        + " from '" + value.getClass().getSimpleName()
864
                        + "' with value '" + value.toString() + "'.");
865
            }
866
        }
867
        if (featureAttributeDescriptor.getType() == DataTypes.GEOMETRY) {
868
            if (value != null) {
869
                Geometry geom = (Geometry) value;
870
                if (geom.getProjection() == null) {
871
                    IProjection proj = ((DefaultFeatureAttributeDescriptor) featureAttributeDescriptor).getSRS(this.storeRef);
872
                    geom.setProjection(proj);
873
                }
874
            }
875
        }
876
        return value;
877
    }
878

    
879
    @Override
880
    public byte[] getByteArray(String name) {
881
        return this.getByteArray(this.data.getType().getIndex(name));
882
    }
883

    
884
    @Override
885
    public byte[] getByteArray(int index) {
886
        return (byte[]) this.get(index);
887
    }
888

    
889
    @Override
890
    public Object[] getArray(String name) {
891
        return this.getArray(this.data.getType().getIndex(name));
892
    }
893

    
894
    @Override
895
    public Object[] getArray(int index) {
896
        return (Object[]) this.get(index);
897
    }
898

    
899
    @Override
900
    public boolean getBoolean(String name) {
901
        return this.getBoolean(this.data.getType().getIndex(name));
902
    }
903

    
904
    @Override
905
    public boolean getBoolean(int index) {
906
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
907
        if (value == null) {
908
            return false;
909
        }
910
        return value;
911
    }
912

    
913
    @Override
914
    public byte getByte(String name) {
915
        return this.getByte(this.data.getType().getIndex(name));
916
    }
917

    
918
    @Override
919
    public byte getByte(int index) {
920
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
921
        if (value == null) {
922
            return 0;
923
        }
924
        return value;
925
    }
926

    
927
    @Override
928
    public java.sql.Date getDate(String name) {
929
        return this.getDate(this.data.getType().getIndex(name));
930
    }
931

    
932
    @Override
933
    public java.sql.Date getDate(int index) {
934
        java.sql.Date value = ((java.sql.Date) this.get(index, java.sql.Date.class, DataTypes.DATE));
935
        return value;
936
    }
937

    
938
    @Override
939
    public java.sql.Time getTime(String name) {
940
        return this.getTime(this.data.getType().getIndex(name));
941
    }
942

    
943
    @Override
944
    public java.sql.Time getTime(int index) {
945
        java.sql.Time value = ((java.sql.Time) this.get(index, java.sql.Time.class, DataTypes.TIME));
946
        return value;
947
    }
948

    
949
    @Override
950
    public java.sql.Timestamp getTimestamp(String name) {
951
        return this.getTimestamp(this.data.getType().getIndex(name));
952
    }
953

    
954
    @Override
955
    public java.sql.Timestamp getTimestamp(int index) {
956
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(index, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
957
        return value;
958
    }
959

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

    
965
    @Override
966
    public double getDouble(int index) {
967

    
968
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
969
        if (value == null) {
970
            return 0;
971
        }
972
        return value;
973
    }
974

    
975
    @Override
976
    public BigDecimal getDecimal(String name) {
977
        return this.getDecimal(this.data.getType().getIndex(name));
978
    }
979

    
980
    @Override
981
    public BigDecimal getDecimal(int index) {
982
        BigDecimal value = ((BigDecimal) this.get(index, BigDecimal.class, DataTypes.DECIMAL));
983
        return value;
984
    }
985

    
986
    @Override
987
    public Feature getFeature(String name) {
988
        return this.getFeature(this.data.getType().getIndex(name));
989
    }
990

    
991
    @Override
992
    public Feature getFeature(int index) {
993
        return (Feature) this.get(index);
994
    }
995

    
996
    @Override
997
    public float getFloat(String name) {
998
        return this.getFloat(this.data.getType().getIndex(name));
999
    }
1000

    
1001
    @Override
1002
    public float getFloat(int index) {
1003
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1004
        if (value == null) {
1005
            return 0;
1006
        }
1007
        return value;
1008
    }
1009

    
1010
    @Override
1011
    public Geometry getGeometry(String name) {
1012
        return this.getGeometry(this.data.getType().getIndex(name));
1013
    }
1014

    
1015
    @Override
1016
    public Geometry getGeometry(int index) {
1017
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1018
    }
1019

    
1020
    @Override
1021
    public int getInt(String name) {
1022
        return this.getInt(this.data.getType().getIndex(name));
1023
    }
1024

    
1025
    @Override
1026
    public int getInt(int index) {
1027
        Integer value = ((Integer) this.get(index, Integer.class, DataTypes.INT));
1028
        if (value == null) {
1029
            return 0;
1030
        }
1031
        return value;
1032
    }
1033

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

    
1039
    @Override
1040
    public long getLong(int index) {
1041
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1042
        if (value == null) {
1043
            return 0;
1044
        }
1045
        return value;
1046
    }
1047

    
1048
    @Override
1049
    public String getString(String name) {
1050
        return this.getString(this.data.getType().getIndex(name));
1051
    }
1052

    
1053
    @Override
1054
    public String getString(int index) {
1055
        return (String) this.get(index, String.class, DataTypes.STRING);
1056
    }
1057

    
1058
    @Override
1059
    public Object getContextValue(String name) {
1060
        name = name.toLowerCase();
1061
        if (name.equals("store")) {
1062
            return this.getStore();
1063
        }
1064

    
1065
        if (name.equals("featuretype")) {
1066
            return this.data.getType();
1067
        }
1068

    
1069
        if (name.equals("feature")) {
1070
            return this;
1071
        }
1072

    
1073
        throw new IllegalArgumentException(name);
1074
    }
1075

    
1076
    @Override
1077
    public Iterator getDataNames() {
1078
        class DataNamesIterator implements Iterator {
1079

    
1080
            Iterator attributeIteraror;
1081

    
1082
            DataNamesIterator(DefaultFeature feature) {
1083
                this.attributeIteraror = feature.getType().iterator();
1084
            }
1085

    
1086
            @Override
1087
            public boolean hasNext() {
1088
                return this.attributeIteraror.hasNext();
1089
            }
1090

    
1091
            @Override
1092
            public Object next() {
1093
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1094
                        .next()).getName();
1095
            }
1096

    
1097
            @Override
1098
            public void remove() {
1099
                throw new UnsupportedOperationException();
1100
            }
1101

    
1102
        }
1103
        return new DataNamesIterator(this);
1104
    }
1105

    
1106
    @Override
1107
    public Object getDataValue(String name) {
1108
        name = name.toLowerCase();
1109
        try {
1110
            return get(name);
1111
        } catch (IllegalArgumentException ex) {
1112
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1113
                return this.getDefaultGeometry();
1114
            }
1115
            throw ex;
1116
        }
1117
    }
1118

    
1119
    @Override
1120
    public Iterator getDataValues() {
1121
        class DataValuesIterator implements Iterator {
1122

    
1123
            DefaultFeature feature;
1124
            int current = 0;
1125

    
1126
            DataValuesIterator(DefaultFeature feature) {
1127
                this.feature = feature;
1128
            }
1129

    
1130
            @Override
1131
            public boolean hasNext() {
1132
                return current < feature.getType().size() - 1;
1133
            }
1134

    
1135
            @Override
1136
            public Object next() {
1137
                return feature.get(current++);
1138
            }
1139

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

    
1145
        }
1146
        return new DataValuesIterator(this);
1147
    }
1148

    
1149
    @Override
1150
    public boolean hasContextValue(String name) {
1151
        name = name.toLowerCase();
1152
        if (name.equals("store")) {
1153
            return true;
1154
        }
1155

    
1156
        if (name.equals("featuretype")) {
1157
            return true;
1158
        }
1159

    
1160
        return name.equals("feature");
1161
    }
1162

    
1163
    @Override
1164
    public boolean hasDataValue(String name) {
1165
        return this.hasValue(name);
1166
    }
1167

    
1168
//    @Override
1169
//    public Time getTime(int index) {
1170
//        return ((Time) this.get(index,Time.class,DataTypes.INSTANT));
1171
//    }
1172
//
1173
//    @Override
1174
//    public Time getTime(String name) {
1175
//        return this.getInstant(this.data.getType().getIndex(name));
1176
//    }
1177
//
1178
//    @Override
1179
//    public Instant getInstant(int index) {
1180
//        return ((Instant) this.get(index,Instant.class,DataTypes.INSTANT));
1181
//    }
1182
//
1183
//    @Override
1184
//    public Instant getInstant(String name) {
1185
//        return this.getInstant(this.data.getType().getIndex(name));
1186
//    }
1187
//
1188
//    @Override
1189
//    public Interval getInterval(int index) {
1190
//        return ((Interval) this.get(index,Interval.class,DataTypes.INTERVAL));
1191
//    }
1192
//
1193
//    @Override
1194
//    public Interval getInterval(String name) {
1195
//        return this.getInterval(this.data.getType().getIndex(name));
1196
//    }
1197
//
1198
    @Override
1199
    public DynObject getAsDynObject() {
1200
        DynObjectFeatureFacade facade = new DynObjectFeatureFacade(this);
1201
        return facade;
1202
    }
1203

    
1204
    @Override
1205
    public String toString() {
1206
        StringBuilder builder = new StringBuilder();
1207
        FeatureAttributeDescriptor[] attributeDescriptors
1208
                = getType().getAttributeDescriptors();
1209
        for (int i = 0; i < attributeDescriptors.length; i++) {
1210
            String name = attributeDescriptors[i].getName();
1211
            Object value = get(name);
1212
            builder.append(value);
1213
            if (i < attributeDescriptors.length - 1) {
1214
                builder.append(", ");
1215
            }
1216
        }
1217
        return builder.toString();
1218
    }
1219

    
1220
    /**
1221
     * @return the inserted
1222
     */
1223
    public boolean isInserted() {
1224
        return inserted;
1225
    }
1226

    
1227
    /**
1228
     * @param inserted the inserted to set
1229
     */
1230
    public void setInserted(boolean inserted) {
1231
        this.inserted = inserted;
1232
//        this.data.setNew(!inserted);
1233
    }
1234

    
1235
    @Override
1236
    public EvaluatorData getEvaluatorData() {
1237
        return this;
1238
    }
1239

    
1240
    @Override
1241
    public int size() {
1242
        return this.data.getType().size();
1243
    }
1244

    
1245
    public boolean isEmpty() {
1246
        return false;
1247
    }
1248

    
1249
    public Iterator<String> iterator() {
1250
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1251
        return new Iterator<String>() {
1252
            @Override
1253
            public boolean hasNext() {
1254
                return x.hasNext();
1255
            }
1256

    
1257
            @Override
1258
            public String next() {
1259
                return x.next().getName();
1260
            }
1261
        };
1262
    }
1263

    
1264
    public boolean containsKey(String key) {
1265
        return this.data.getType().get(key) != null;
1266
    }
1267

    
1268
    @Override
1269
    public String getLabelOfValue(String name) {
1270
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1271
        if (attrdesc == null) {
1272
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1273
        }
1274
        Object value = this.get(attrdesc.getIndex());
1275
        String label = attrdesc.getLabelOfValue(value);
1276
        return label;
1277
    }
1278

    
1279
    @Override
1280
    public void setExtraValue(String name, Object value) {
1281
        if (this.extraValues == null) {
1282
            this.extraValues = new HashMap<>();
1283
        }
1284
        this.extraValues.put(name, value);
1285
    }
1286

    
1287
    public Object getExtraColumnValue(String name) {
1288
        Object value;
1289
        if (this.extraValues != null) {
1290
            if (this.extraValues.containsKey(name)) {
1291
                return this.extraValues.get(name);
1292
            }
1293
        }
1294
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1295
        int index = columns.getIndexOf(name);
1296
        if (index < 0) {
1297
            throw new RuntimeException("Not extra column value found");
1298
        }
1299
        if (extraValuesData == null) {
1300
            extraValuesData = new Object[columns.size()];
1301
        }
1302
        EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1303
        value = extraValuesData[index];
1304
        if (value != null) {
1305
            return value;
1306
        }
1307
        value = this.getExtraValue(name);
1308
        extraValuesData[index] = value;
1309
        if (value == null && !this.hasExtraValue(name)) {
1310
            if (attrdesc.getFeatureAttributeEmulator() != null) {
1311
                value = attrdesc.getFeatureAttributeEmulator().get(this);
1312
                extraValuesData[index] = value;
1313
            }
1314
        }
1315
        return value;
1316
    }
1317

    
1318
    @Override
1319
    public Object getExtraValue(String name) {
1320
        Object value = this.data.getExtraValue(name);
1321
        return value;
1322
    }
1323

    
1324
    @Override
1325
    public boolean hasExtraValue(String name) {
1326
        return this.data.hasExtraValue(name);
1327
    }
1328

    
1329
    private boolean hasExtraColumnValue(String name) {
1330
        if (this.extraValues != null) {
1331
            if (this.extraValues.containsKey(name)) {
1332
                return true;
1333
            }
1334
        }
1335
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1336
        int index = columns.getIndexOf(name);
1337
        if (index >= 0) {
1338
            return true;
1339
        }
1340
        return false;
1341
    }
1342

    
1343
    @Override
1344
    public boolean hasValue(String name) {
1345
        name = name.toLowerCase();
1346
        return this.data.getType().getIndex(name) >= 0
1347
                || hasExtraValue(name)
1348
                || hasExtraColumnValue(name);
1349
    }
1350

    
1351
    @Override
1352
    public Object getExtraValue(int index) {
1353
        return this.data.getExtraValue(index);
1354
    }
1355

    
1356
    @Override
1357
    public JsonObject toJson() {
1358
        JsonObjectBuilder builder = this.toJsonBuilder();
1359
        return builder.build();
1360
    }
1361

    
1362
    @Override
1363
    public JsonObjectBuilder toJsonBuilder() {
1364
        JsonObjectBuilder builder = Json.createObjectBuilder();
1365
        Date date;
1366
        Geometry geom;
1367
        FeatureType ft = this.getType();
1368
        for (FeatureAttributeDescriptor desc : ft) {
1369
            if (desc.isComputed()) {
1370
                continue;
1371
            }
1372
            switch (desc.getType()) {
1373
                case DataTypes.GEOMETRY:
1374
                    geom = this.getGeometry(desc.getIndex());
1375
                    if (geom != null) {
1376
                        builder.add(desc.getName(), geom.convertToHexWKBQuietly());
1377
                    }
1378
                    break;
1379
                case DataTypes.BOOLEAN:
1380
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1381
                    break;
1382
                case DataTypes.BYTE:
1383
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1384
                    break;
1385
                case DataTypes.INT:
1386
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1387
                    break;
1388
                case DataTypes.LONG:
1389
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1390
                    break;
1391
                case DataTypes.DOUBLE:
1392
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1393
                    break;
1394
                case DataTypes.FLOAT:
1395
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1396
                    break;
1397
                case DataTypes.DATE:
1398
                    // Format date as ISO 8601
1399
                    date = this.getDate(desc.getIndex());
1400
                    if (date == null) {
1401
                        builder.addNull(desc.getName());
1402
                    } else {
1403
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1404
                        String value = DateTimeFormatter.ISO_DATE.format(localDateTime);
1405
                        builder.add(desc.getName(), value);
1406
                    }
1407
                    break;
1408
                case DataTypes.TIMESTAMP:
1409
                    // Format date as ISO 8601
1410
                    date = this.getTimestamp(desc.getIndex());
1411
                    if (date == null) {
1412
                        builder.addNull(desc.getName());
1413
                    } else {
1414
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1415
                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1416
                        builder.add(desc.getName(), value);
1417
                    }
1418
                    break;
1419
                case DataTypes.TIME:
1420
                    // Format date as ISO 8601
1421
                    date = this.getTime(desc.getIndex());
1422
                    if (date == null) {
1423
                        builder.addNull(desc.getName());
1424
                    } else {
1425
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1426
                        String value = DateTimeFormatter.ISO_TIME.format(localDateTime);
1427
                        builder.add(desc.getName(), value);
1428
                    }
1429
                    break;
1430
                default:
1431
                    builder.add(desc.getName(), this.getStringOrDefault(desc.getIndex(), ""));
1432
            }
1433
        }
1434
        return builder;
1435
    }
1436

    
1437
    @Override
1438
    public List<String> getKeys() {
1439
        List<String> l = new ArrayList<>();
1440
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1441
            l.add(descriptor.getName());
1442
        }
1443
        return l;
1444
    }
1445

    
1446
}