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

History | View | Annotate | Download (45.2 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.spi.DefaultFeatureProvider;
62
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
63
import org.gvsig.fmap.geom.Geometry;
64
import org.gvsig.fmap.geom.primitive.Envelope;
65
import org.gvsig.json.Json;
66
import org.gvsig.json.JsonObjectBuilder;
67
import org.gvsig.tools.ToolsLocator;
68
import org.gvsig.tools.dataTypes.Coercion;
69
import org.gvsig.tools.dataTypes.CoercionException;
70
import org.gvsig.tools.dataTypes.DataType;
71
import org.gvsig.tools.dataTypes.DataTypesManager;
72
import org.gvsig.tools.dataTypes.impl.coercion.CoerceToString;
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 (attribute.isReadOnly()) {
170
            throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
171
        }
172
        FeatureAttributeEmulator emulator = attribute.getFeatureAttributeEmulator();
173
        if (emulator != null) {
174
            emulator.set((EditableFeature) this, value);
175
            return;
176
        }
177

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

    
187
        }
188

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

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

    
197
        Class objectClass = attribute.getObjectClass();
198
        if (objectClass != null) {
199
            if (objectClass.isInstance(value)) {
200
                if (attribute.getType() == DataTypes.DECIMAL) {
201
                    BigDecimal d = (BigDecimal) value;
202
                    if (d.scale() == attribute.getScale() && d.precision() <= attribute.getPrecision()) {
203
                        this.data.set(i, value);
204
                        return;
205
                    }
206
                } else {
207
                    this.data.set(i, value);
208
                    return;
209
                }
210
            }
211
            DataProfile dataProfile = attribute.getDataProfile();
212
            if (dataProfile != null) {
213
                try {
214
                    value = dataProfile.coerce(
215
                            attribute.getDataType(),
216
                            value,
217
                            attribute.getTags()
218
                    );
219
                } catch (CoercionException e) {
220

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
564
    class UnableToGetReferenceException extends BaseRuntimeException {
565

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

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

    
580
        }
581

    
582
    }
583

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
803
                };
804
            }
805

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1072
        throw new IllegalArgumentException(name);
1073
    }
1074

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

    
1079
            Iterator attributeIteraror;
1080

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

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

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

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

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

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

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

    
1122
            DefaultFeature feature;
1123
            int current = 0;
1124

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1445
}