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

History | View | Annotate | Download (63.6 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl;
25

    
26
import java.lang.ref.WeakReference;
27
import java.math.BigDecimal;
28
import java.time.LocalDateTime;
29
import java.time.ZoneId;
30
import java.time.format.DateTimeFormatter;
31
import java.util.ArrayList;
32
import java.util.Date;
33
import java.util.HashMap;
34
import java.util.HashSet;
35
import java.util.Iterator;
36
import java.util.List;
37
import java.util.Map;
38
import java.util.Objects;
39
import java.util.Set;
40
import java.util.function.Predicate;
41
import javax.json.JsonObject;
42
import org.apache.commons.lang3.ArrayUtils;
43
import org.apache.commons.lang3.StringUtils;
44
import org.cresques.cts.IProjection;
45
import org.gvsig.expressionevaluator.Expression;
46
import org.gvsig.expressionevaluator.ExpressionBuilder;
47
import org.gvsig.expressionevaluator.ExpressionUtils;
48
import org.gvsig.fmap.dal.DALLocator;
49
import org.gvsig.fmap.dal.DataTypes;
50
import org.gvsig.fmap.dal.SupportTransactions;
51
import org.gvsig.fmap.dal.exception.DataEvaluatorRuntimeException;
52
import org.gvsig.fmap.dal.exception.DataException;
53
import org.gvsig.fmap.dal.feature.DataProfile;
54
import org.gvsig.fmap.dal.feature.EditableFeature;
55
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
56
import org.gvsig.fmap.dal.feature.Feature;
57
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
58
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
59
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
60
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
61
import org.gvsig.fmap.dal.feature.FeatureReference;
62
import org.gvsig.fmap.dal.feature.FeatureStore;
63
import org.gvsig.fmap.dal.feature.FeatureType;
64
import org.gvsig.fmap.dal.feature.ForeingKey;
65
import org.gvsig.fmap.dal.feature.exception.IllegalValueException;
66
import org.gvsig.fmap.dal.feature.exception.SetReadOnlyAttributeException;
67
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
68
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
69
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
70
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
71
import org.gvsig.fmap.geom.Geometry;
72
import org.gvsig.fmap.geom.primitive.Envelope;
73
import org.gvsig.json.Json;
74
import org.gvsig.json.JsonArrayBuilder;
75
import org.gvsig.json.JsonObjectBuilder;
76
import org.gvsig.tools.ToolsLocator;
77
import org.gvsig.tools.dataTypes.Coercion;
78
import org.gvsig.tools.dataTypes.CoercionException;
79
import org.gvsig.tools.dataTypes.DataType;
80
import org.gvsig.tools.dataTypes.DataTypesManager;
81
import org.gvsig.tools.dispose.DisposeUtils;
82
import org.gvsig.tools.dynobject.DynField;
83
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_AGGREGATE;
84
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_COLLABORATION;
85
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_COMPOSITION;
86
import org.gvsig.tools.dynobject.DynObject;
87
import org.gvsig.tools.evaluator.Evaluator;
88
import org.gvsig.tools.evaluator.EvaluatorData;
89
import org.gvsig.tools.evaluator.EvaluatorException;
90
import org.gvsig.tools.exception.BaseException;
91
import org.gvsig.tools.exception.BaseRuntimeException;
92
import org.gvsig.tools.lang.Cloneable;
93
import org.gvsig.tools.util.Bitmask;
94
import org.slf4j.Logger;
95
import org.slf4j.LoggerFactory;
96

    
97
@SuppressWarnings("UseSpecificCatch")
98
public class DefaultFeature implements Feature, EvaluatorData, Cloneable {
99

    
100
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeature.class);
101

    
102
    private static DataTypesManager dataTypesManager = null;
103
    protected FeatureProvider data;
104
    protected FeatureReference reference;
105
    private WeakReference storeRef;
106

    
107
    private boolean inserted = false;
108
    private Object[] extraValuesData;
109
    private Map<String, Object> extraValues; // not persistent
110

    
111
    /*
112
         * Usar con mucha precaucion o mejor no usar. Lo precisa el
113
         * DefaultFeatureSet en la ordenacion.
114
     */
115
    public DefaultFeature(FeatureStore store) {
116
        this.storeRef = new WeakReference(store);
117
        this.reference = null;
118
    }
119

    
120
    public DefaultFeature(FeatureStore store, FeatureProvider data) {
121
        this.data = data;
122
        this.extraValuesData = null;
123
        this.storeRef = new WeakReference(store);
124
        this.reference = null;
125
        this.inserted = !data.isNew();
126
    }
127

    
128
    DefaultFeature(DefaultFeature feature) {
129
        this.data = feature.data.getCopy();
130
        this.extraValuesData = ArrayUtils.clone(feature.extraValuesData);
131
        this.storeRef = feature.storeRef;
132
        this.reference = feature.reference;
133
        this.inserted = feature.isInserted();
134
    }
135

    
136
    public DefaultFeature(FeatureType targetType, Feature sourceFeature) {
137
        DefaultFeature defaultFeature = (DefaultFeature) sourceFeature;
138
        this.data = new DefaultFeatureProvider(targetType, (DefaultFeatureProvider) defaultFeature.getData());
139
        this.extraValuesData = null;
140
        this.storeRef = defaultFeature.storeRef;
141
        this.reference = defaultFeature.reference;
142
        this.inserted = defaultFeature.isInserted();
143

    
144
        FeatureType sourceType = sourceFeature.getType();
145

    
146
        for (FeatureAttributeDescriptor targetAttrDescriptor : targetType) {
147
            if (targetAttrDescriptor.isComputed()) {
148
                continue;
149
            }
150
            int sourceIndex = sourceType.getIndex(targetAttrDescriptor.getName());
151
            if (sourceIndex < 0) {
152
                continue;
153
            }
154
            Object value = sourceFeature.get(sourceIndex);
155
            if (value == null && !targetAttrDescriptor.allowNull()) {
156
                continue;
157
            }
158
            this.setforced(targetAttrDescriptor.getIndex(), targetAttrDescriptor, value);
159
        }
160
    }
161

    
162
    public void setData(FeatureProvider data) {
163
        this.data = data;
164
        this.extraValuesData = null;
165
        this.reference = null;
166
        this.inserted = true;
167
    }
168

    
169
    public FeatureProvider getData() {
170
        return this.data;
171
    }
172

    
173
    protected DataTypesManager getDataTypesManager() {
174
        if (dataTypesManager == null) {
175
            dataTypesManager = ToolsLocator.getDataTypesManager();
176
        }
177
        return dataTypesManager;
178
    }
179

    
180
    public boolean canSetValue(String name) {
181
        return this.canSetValue(this.getType().getAttributeDescriptor(name), null);
182
    }
183

    
184
    public boolean canSetValue(FeatureAttributeDescriptor attr,Predicate<FeatureAttributeDescriptor> filter) {
185
        // helper function to use in copyFrom
186
        if (attr==null  ) {
187
            return false;
188
        }
189
        if (attr.isAutomatic()  || attr.isComputed() ) {
190
            return false;
191
        }
192
        if( this.isInserted() &&  attr.isReadOnly()) {
193
            return false;
194
        }
195
        if( filter!=null && !filter.test(attr) ) {
196
            return false;
197
        }
198
        return true;
199
    }
200

    
201
    protected void set(FeatureAttributeDescriptor attribute, Object value) {
202
        int i = attribute.getIndex();
203

    
204
        if( this.isInserted() ) {
205
            if (attribute.isReadOnly()) {
206
                throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
207
            }
208
        } else {
209
            if (attribute.isComputed()) {
210
                throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
211
            }
212
        }
213
        FeatureAttributeEmulator emulator = attribute.getFeatureAttributeEmulator();
214
        if (emulator != null) {
215
            emulator.set((EditableFeature) this, value);
216
            return;
217
        }
218

    
219
        if (value == null) {
220
            if (!attribute.allowNull()) {
221
                if (!attribute.isAutomatic()) {
222
                    throw new IllegalValueException(attribute, value);
223
                }
224
            }
225
            this.data.set(i, null);
226
            return;
227

    
228
        }
229

    
230
        if (attribute.getFeatureAttributeGetter() != null) {
231
            value = attribute.getFeatureAttributeGetter().setter(value);
232
        }
233
        this.setforced(i, attribute, value);
234
    }
235

    
236
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
237

    
238
        Class objectClass = attribute.getObjectClass();
239
        if (objectClass != null) {
240
            if (objectClass.isInstance(value)) {
241
                if (attribute.getType() == DataTypes.DECIMAL) {
242
                    BigDecimal d = (BigDecimal) value;
243
                    if (d.scale() == attribute.getScale() && d.precision() <= attribute.getPrecision()) {
244
                        this.data.set(i, value);
245
                        return;
246
                    }
247
                } else if (attribute.getType() == DataTypes.GEOMETRY) {
248
                    if (!attribute.getGeomType().equals(((Geometry) value).getGeometryType())) {
249
                        try {
250
                            Coercion coercer = attribute.getDataType().getCoercion();
251
                            value = coercer.coerce(value, attribute.getCoercionContext());
252
                        } catch (CoercionException e) {
253
                            throw new IllegalArgumentException("Can't convert to "
254
                                    + attribute.getDataType().getName()
255
                                    + " from '"
256
                                    + value == null ? "NULL" : value.getClass().getName()
257
                                            + "' with value '"
258
                                            + Objects.toString(value)
259
                                            + "' and context '"
260
                                            + attribute.getCoercionContext()
261
                                            + "'.",e);
262
                        }
263
                    } 
264
                    this.data.set(i, value);
265
                    return;
266
                } else {
267
                    this.data.set(i, value);
268
                    return;
269
                }
270
            }
271
            DataProfile dataProfile = attribute.getDataProfile();
272
            if (dataProfile != null) {
273
                try {
274
                    value = dataProfile.coerce(
275
                            attribute.getDataType(),
276
                            value,
277
                            attribute.getTags()
278
                    );
279
                } catch (CoercionException e) {
280

    
281
                }
282
            }
283
            try {
284
                Coercion coercer = attribute.getDataType().getCoercion();
285
                if (attribute.getType() == DataTypes.STRING && value instanceof Boolean) {
286
                    value = coercer.coerce(value, attribute.getCoercionContext());
287
                    value = StringUtils.left((String) value, attribute.getSize());
288
                } else {
289
                    value = coercer.coerce(value, attribute.getCoercionContext());
290
                }
291
            } catch (CoercionException e) {
292
                throw new IllegalArgumentException("Can't assign value [" + 
293
                        toStringQuietly(value)+
294
                        "] of type '"+
295
                        (value == null ? "NULL" : value.getClass().getName())+
296
                        "' to field '"+
297
                        attribute.getName()+
298
                        "' of type "+
299
                        attribute.getDataType().getName()+
300
                        "."
301
                ,e);
302
            }
303
        }
304
        this.data.set(i, value);
305
    }
306

    
307
    private String toStringQuietly(Object v) {
308
        try {
309
            return Objects.toString(v);
310
        } catch(Throwable t) {
311
            return "ERROR";
312
        }
313
    }
314
    
315
    private Object get(int index, Class theClass, int type) {
316
        Object value = this.get(index);
317
        if (theClass.isInstance(value)) {
318
            return value;
319
        }
320
        try {
321
            return this.getDataTypesManager().coerce(type, value, this.getType().getAttributeDescriptor(index).getCoercionContext());
322
        } catch (CoercionException e) {
323

    
324
            if (value == null) {
325
                return null;
326
            }
327
            throw new IllegalArgumentException(
328
                    "Can't convert to " + theClass.getName()
329
                    + " from '" + value.getClass().getName()
330
                    + "' with value '" + value.toString() + "'.");
331
        }
332
    }
333

    
334
    public void initializeValues() {
335
        FeatureType type = this.getType();
336
        for (FeatureAttributeDescriptor attribute : type) {
337
            if (attribute.isAutomatic() || attribute.isReadOnly()
338
                    || attribute.isComputed()) {
339
                continue;
340
            }
341
            if (attribute.getDefaultValue() == null && !attribute.allowNull()) {
342
                continue;
343
            }
344
            Object value = attribute.getDefaultValue();
345
            if (value instanceof CharSequence) {
346
                String s = ((CharSequence) value).toString();
347
                if (ExpressionUtils.isDynamicText(s)) {
348
                    try {
349
                        value = ExpressionUtils.evaluateDynamicText(s);
350
                    } catch (Throwable th) {
351
                        value = null;
352
                    }
353
                }
354
            }
355
            this.set(attribute, value);
356
        }
357
    }
358

    
359
    public void clear() {
360
        initializeValues();
361
    }
362

    
363
    public void initializeValues(Feature feature) {
364
        FeatureType myType = this.getType();
365
        FeatureType type = feature.getType();
366
        extraValuesData = null;
367
        for (FeatureAttributeDescriptor attribute : type) {
368
            FeatureAttributeDescriptor myAttribute = myType.getAttributeDescriptor(attribute.getName());
369
            if (myAttribute != null) {
370
                this.set(myAttribute, feature.get(attribute.getIndex()));
371
            }
372
        }
373
    }
374

    
375
    @Override
376
    public FeatureStore getStore() {
377
        return (FeatureStore) this.storeRef.get();
378
    }
379

    
380
    @Override
381
    public FeatureType getType() {
382
        return this.data.getType();
383
    }
384

    
385
    @Override
386
    public EditableFeature getEditable() {
387
        return new DefaultEditableFeature(this);
388
    }
389

    
390
    @Override
391
    public Feature getCopy() {
392
        return new DefaultFeature(this);
393
    }
394

    
395
    @Override
396
    @SuppressWarnings("CloneDoesntCallSuperClone")
397
    public Object clone() throws CloneNotSupportedException {
398
        return new DefaultFeature(this);
399
    }
400

    
401
    @Override
402
    public FeatureReference getReference() {
403
        if(!this.getType().supportReferences()){
404
            return null;
405
        }
406
        if (this.reference == null) {
407
            if (!isInserted()) {
408
                return null;
409
            }
410
            reference = FeatureReferenceFactory.createFromFeature(this);
411
        }
412
        return this.reference;
413
    }
414

    
415
    @Override
416
    public Object getOrDefault(String name, Object defaultValue) {
417
        int index = this.data.getType().getIndex(name);
418
        if (index < 0) {
419
            return defaultValue;
420
        }
421
        return this.get(index);
422
    }
423
    
424
    @Override
425
    public Object getOrDefault(String name, int type, Object defaultValue) {
426
        DataType dataType = ToolsLocator.getDataTypesManager().get(type);
427
        return getOrDefault(name, dataType, defaultValue);
428
    }
429
    
430
    @Override
431
    public Object getOrDefault(String name, DataType type, Object defaultValue) {
432
        int index = this.data.getType().getIndex(name);
433
        if (index < 0) {
434
            return defaultValue;
435
        }
436
        try {
437
            Object value = this.get(index);
438
            if(value == null){
439
                return defaultValue;
440
            }
441
            return type.coerce(value);
442
        } catch (Throwable th) {
443
            return defaultValue;
444
        }
445
    }
446

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

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

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

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

    
499
    @Override
500
    public float getFloatOrDefault(String name, float defaultValue) {
501
        int index = this.data.getType().getIndex(name);
502
        if (index < 0) {
503
            return defaultValue;
504
        }
505
        try {
506
            return this.getFloat(index);
507
        } catch (Throwable th) {
508
            return defaultValue;
509
        }
510
    }
511

    
512
    @Override
513
    public double getDoubleOrDefault(String name, double defaultValue) {
514
        int index = this.data.getType().getIndex(name);
515
        if (index < 0) {
516
            return defaultValue;
517
        }
518
        try {
519
            return this.getDouble(index);
520
        } catch (Throwable th) {
521
            return defaultValue;
522
        }
523
    }
524

    
525
    @Override
526
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
527
        int index = this.data.getType().getIndex(name);
528
        if (index < 0) {
529
            return defaultValue;
530
        }
531
        try {
532
            return this.getDecimal(index);
533
        } catch (Throwable th) {
534
            return defaultValue;
535
        }
536
    }
537

    
538
    @Override
539
    public Date getDateOrDefault(String name, Date defaultValue) {
540
        int index = this.data.getType().getIndex(name);
541
        if (index < 0) {
542
            return defaultValue;
543
        }
544
        try {
545
            return this.getDate(index);
546
        } catch (Throwable th) {
547
            return defaultValue;
548
        }
549
    }
550

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

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

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

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

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

    
611
    @Override
612
    public float getFloatOrDefault(int index, float defaultValue) {
613
        if (index < 0 || index >= this.data.getType().size()) {
614
            return defaultValue;
615
        }
616
        try {
617
            return this.getFloat(index);
618
        } catch (Throwable th) {
619
            return defaultValue;
620
        }
621
    }
622

    
623
    @Override
624
    public double getDoubleOrDefault(int index, double defaultValue) {
625
        if (index < 0 || index >= this.data.getType().size()) {
626
            return defaultValue;
627
        }
628
        try {
629
            return this.getDouble(index);
630
        } catch (Throwable th) {
631
            return defaultValue;
632
        }
633
    }
634

    
635
    @Override
636
    public BigDecimal getDecimalOrDefault(int index, BigDecimal defaultValue) {
637
        if (index < 0 || index >= this.data.getType().size()) {
638
            return defaultValue;
639
        }
640
        try {
641
            return this.getDecimal(index);
642
        } catch (Throwable th) {
643
            return defaultValue;
644
        }
645
    }
646

    
647
    @Override
648
    public Date getDateOrDefault(int index, Date defaultValue) {
649
        if (index < 0 || index >= this.data.getType().size()) {
650
            return defaultValue;
651
        }
652
        try {
653
            return this.getDate(index);
654
        } catch (Throwable th) {
655
            return defaultValue;
656
        }
657
    }
658

    
659
    @Override
660
    public void validate(int check) throws DataException {
661
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, check);
662
    }
663

    
664
    class UnableToGetReferenceException extends BaseRuntimeException {
665

    
666
        /**
667
         *
668
         */
669
        private static final long serialVersionUID = 1812805035204824163L;
670

    
671
        /**
672
         * @param exception
673
         */
674
        @SuppressWarnings("OverridableMethodCallInConstructor")
675
        public UnableToGetReferenceException(BaseException exception) {
676
            super("Unable to get reference", "_UnableToGetReferenceException",
677
                    serialVersionUID);
678
            this.initCause(exception);
679

    
680
        }
681

    
682
    }
683

    
684
    @Override
685
    public List getSRSs() {
686
        // TODO Auto-generated method stub
687
        return null;
688
    }
689

    
690
    @Override
691
    public Envelope getDefaultEnvelope() {
692
        Envelope envelope = this.data.getDefaultEnvelope();
693
        if (envelope == null) {
694
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
695
            if (i < 0) {
696
                return null;
697
            }
698
            Geometry geom = this.getDefaultGeometry();
699
            if (geom != null) {
700
                envelope = geom.getEnvelope();
701
            }
702
        }
703
        return envelope;
704
    }
705

    
706
    @Override
707
    public Geometry getDefaultGeometry() {
708
        Geometry geom = this.data.getDefaultGeometry();
709
        if (geom == null) {
710
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
711
            if (i < 0) {
712
                return null;
713
            }
714
            Object x = this.get(i);
715
            if (x instanceof Geometry) {
716
                geom = (Geometry) x;
717
            } else {
718
                geom = this.getGeometry(i);
719
            }
720
        }
721
        if (geom != null) {
722
            if (geom.getProjection() == null) {
723
                FeatureType type = this.getType();
724
                DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
725
                IProjection proj = attrdesc.getSRS(this.storeRef);
726
                geom.setProjection(proj);
727
            }
728
        }
729
        return geom;
730
    }
731

    
732
//    @Override
733
//    public Time getDefaultTime() {
734
//            Time time = this.data.getDefaultTime();
735
//        if( time == null ) {
736
//            int i = this.data.getType().getDefaultTimeAttributeIndex();
737
//            Object x = this.get(i);
738
//            if( x instanceof Time ) {
739
//                time = (Time) x;
740
//            } else {
741
//                time = this.getTime(i);
742
//            }
743
//        }
744
//        return time;
745
//    }
746
//
747
    @Override
748
    public IProjection getDefaultSRS() {
749
        IProjection srs = this.data.getType().getDefaultSRS();
750
        if (srs == null) {
751
            FeatureType type = this.getType();
752
            DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
753
            srs = attrdesc.getSRS(this.storeRef);
754
        }
755
        return srs;
756
    }
757

    
758
    @Override
759
    public List getGeometries() {
760
        // TODO Auto-generated method stub
761
        return null;
762
    }
763

    
764
    @Override
765
    public Object getFromProfile(int index) {
766
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
767
        Object value = this.get(index);
768
        String profileName = descriptor.getDataProfileName();
769
        if (StringUtils.isBlank(profileName)) {
770
            return value;
771
        }
772
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
773
        if (profile == null) {
774
            return value;
775
        }
776
        return profile.createData(value, descriptor.getTags());
777
    }
778

    
779
    @Override
780
    public Object getFromProfile(String name) {
781
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
782
        return this.getFromProfile(descriptor.getIndex());
783
    }
784

    
785
    private Object get(String name, Class theClass, int type) {
786
        Object value = this.get(name);
787
        if (theClass.isInstance(value)) {
788
            return value;
789
        }
790
        try {
791
            return this.getDataTypesManager().coerce(type, value);
792
        } catch (CoercionException e) {
793

    
794
            if (value == null) {
795
                return null;
796
            }
797
            throw new IllegalArgumentException(
798
                    "Can't convert to " + theClass.getName()
799
                    + " from '" + value.getClass().getName()
800
                    + "' with value '" + value.toString() + "'.");
801
        }
802
    }
803

    
804
    @Override
805
    public Object get(String name) {
806
        int index = this.data.getType().getIndex(name);
807
        if (index < 0) {
808
            // buscamos en los extra cols
809
            if (hasExtraColumnValue(name)) {
810
                return getExtraColumnValue(name);
811
            }
812
            if (hasExtraValue(name)) {
813
                return getExtraValue(name);
814
            }
815
            // y si esta ahi return
816
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
817
        }
818
        return this.get(index);
819
    }
820

    
821
    @Override
822
    public boolean isNull(int index) {
823
        FeatureType type = this.data.getType();
824
        if (index < 0 || index >= type.size()) {
825
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
826
        }
827
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
828
        if (!this.data.getType().hasEvaluators()) {
829
            return this.data.get(index) == null;
830
        }
831
        Evaluator eval = attribute.getEvaluator();
832
        if (eval == null) {
833
            return this.data.get(index) == null;
834
        }
835
        Object value = this.data.get(index);
836
        if (value != null) {
837
            return true;
838
        }
839
        try {
840
            value = eval.evaluate(this);
841
        } catch (EvaluatorException e) {
842
            throw new DataEvaluatorRuntimeException(e);
843
        }
844
        this.data.set(index, value);
845
        return value == null;
846
    }
847

    
848
    @Override
849
    public boolean isNull(String name) {
850
        int index = this.data.getType().getIndex(name);
851
        if (index < 0) {
852
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
853
        }
854
        return this.isNull(index);
855
    }
856

    
857
    public boolean has_key(String key) {
858
        Object x = this.getType().get(key);
859
        return x != null;
860
    }
861

    
862
    public List<String> keys() {
863
        List<String> ks = new ArrayList<>();
864
        for (FeatureAttributeDescriptor attr : this.getType()) {
865
            ks.add(attr.getName());
866
        }
867
        return ks;
868
    }
869

    
870
    public Iterator<String> iterkeys() {
871
        final Iterator it = this.getType().iterator();
872
        return new Iterator<String>() {
873
            @Override
874
            public boolean hasNext() {
875
                return it.hasNext();
876
            }
877

    
878
            @Override
879
            public String next() {
880
                return ((FeatureAttributeDescriptor) it.next()).getName();
881
            }
882

    
883
            @Override
884
            public void remove() {
885
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
886
            }
887
        };
888
    }
889

    
890
    public Iterator iteritems() {
891
        final Iterator it = this.getType().iterator();
892
        return new Iterator<Map.Entry>() {
893
            @Override
894
            public boolean hasNext() {
895
                return it.hasNext();
896
            }
897

    
898
            @Override
899
            public Map.Entry next() {
900
                final String name = ((FeatureAttributeDescriptor) it.next()).getName();
901
                return new Map.Entry<String, Object>() {
902
                    @Override
903
                    public String getKey() {
904
                        return name;
905
                    }
906

    
907
                    @Override
908
                    public Object getValue() {
909
                        return get(name);
910
                    }
911

    
912
                    @Override
913
                    public Object setValue(Object value) {
914
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
915
                    }
916

    
917
                };
918
            }
919

    
920
            @Override
921
            public void remove() {
922
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
923
            }
924
        };
925
    }
926

    
927
    @Override
928
    public Object get(int index) {
929
        FeatureType type = this.data.getType();
930
        if (index < 0 || index >= type.size()) {
931
            throw new IllegalArgumentException("Attribute index '" + index + "' out of range (0 to " + this.data.getType().size() + ".");
932
        }
933
        Object value = this.data.get(index);
934
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
935
        if (type.hasEvaluators()) {
936
            Evaluator eval = attribute.getEvaluator();
937
            if (eval != null) {
938
                if (value == null) { // Ya hemos calculado el campo ?
939
                    // FIXME: para comprobar si esta calculado usar un array especifico.
940
                    try {
941
                        value = eval.evaluate(this);
942
                    } catch (EvaluatorException e) {
943
                        throw new DataEvaluatorRuntimeException(e);
944
                    }
945
                    this.data.set(index, value);
946
                }
947
            }
948
        }
949
        value = get(attribute, value);
950
        return value;
951
    }
952

    
953
    private Object get(FeatureAttributeDescriptor featureAttributeDescriptor, Object value) {
954
        FeatureAttributeEmulator emulator = featureAttributeDescriptor.getFeatureAttributeEmulator();
955
        if (emulator != null) {
956
//            int index = featureAttributeDescriptor.getIndex();
957
//            value = this.data.get(index);
958
//            if( value==null ) {
959
            value = this.getExtraValue(featureAttributeDescriptor.getName());
960
            if (value==null) {
961
                value = emulator.get(this);
962
            }
963
//                this.data.set(index,value);
964
//            }
965
        } else {
966
            FeatureAttributeGetter getter = featureAttributeDescriptor.getFeatureAttributeGetter();
967
            if (getter != null) {
968
                value = getter.getter(value);
969
            }
970
        }
971
        value = coerce(featureAttributeDescriptor, value);
972
        return value;
973
    }
974
    
975
    private Object coerce(FeatureAttributeDescriptor attr, Object value) {
976
        if( value == null ) {
977
            return null;
978
        }
979
        DataType dataType = attr.getDataType();
980
        Class<? extends DataType> theClass = dataType.getDefaultClass();
981
        if (theClass != null && !theClass.isInstance(value)) {
982
            try {
983
                value = this.getDataTypesManager().coerce(dataType.getType(), value);
984
            } catch (CoercionException e) {
985
                throw new IllegalArgumentException(
986
                        "Can't convert to " + theClass.getSimpleName()
987
                        + " from '" + value==null? "NULL":value.getClass().getSimpleName()
988
                        + "' with value '" + Objects.toString(value) + "'.");
989
            }
990
        }
991
        if (attr.getType() == DataTypes.GEOMETRY) {
992
            if (value != null) {
993
                Geometry geom = (Geometry) value;
994
                if (geom.getProjection() == null) {
995
                    IProjection proj = ((DefaultFeatureAttributeDescriptor) attr).getSRS(this.storeRef);
996
                    geom.setProjection(proj);
997
                }
998
            }
999
        }
1000
        return value;
1001
    }
1002

    
1003
    @Override
1004
    public byte[] getByteArray(String name) {
1005
        return (byte[]) this.get(name);
1006
    }
1007

    
1008
    @Override
1009
    public byte[] getByteArray(int index) {
1010
        return (byte[]) this.get(index);
1011
    }
1012

    
1013
    @Override
1014
    public Object[] getArray(String name) {
1015
        return (Object[]) this.get(name);
1016
    }
1017

    
1018
    @Override
1019
    public Object[] getArray(int index) {
1020
        return (Object[]) this.get(index);
1021
    }
1022

    
1023
    @Override
1024
    public boolean getBoolean(String name) {
1025
        Boolean value = ((Boolean) this.get(name, Boolean.class, DataTypes.BOOLEAN));
1026
        if (value == null) {
1027
            return false;
1028
        }
1029
        return value;
1030
    }
1031

    
1032
    @Override
1033
    public boolean getBoolean(int index) {
1034
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
1035
        if (value == null) {
1036
            return false;
1037
        }
1038
        return value;
1039
    }
1040

    
1041
    @Override
1042
    public byte getByte(String name) {
1043
        Byte value = ((Byte) this.get(name, Byte.class, DataTypes.BYTE));
1044
        if (value == null) {
1045
            return 0;
1046
        }
1047
        return value;
1048
    }
1049

    
1050
    @Override
1051
    public byte getByte(int index) {
1052
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
1053
        if (value == null) {
1054
            return 0;
1055
        }
1056
        return value;
1057
    }
1058

    
1059
    @Override
1060
    public java.sql.Date getDate(String name) {
1061
        java.sql.Date value = ((java.sql.Date) this.get(name, java.sql.Date.class, DataTypes.DATE));
1062
        return value;
1063
    }
1064

    
1065
    @Override
1066
    public java.sql.Date getDate(int index) {
1067
        java.sql.Date value = ((java.sql.Date) this.get(index, java.sql.Date.class, DataTypes.DATE));
1068
        return value;
1069
    }
1070

    
1071
    @Override
1072
    public java.sql.Time getTime(String name) {
1073
        java.sql.Time value = ((java.sql.Time) this.get(name, java.sql.Time.class, DataTypes.TIME));
1074
        return value;
1075
    }
1076

    
1077
    @Override
1078
    public java.sql.Time getTime(int index) {
1079
        java.sql.Time value = ((java.sql.Time) this.get(index, java.sql.Time.class, DataTypes.TIME));
1080
        return value;
1081
    }
1082

    
1083
    @Override
1084
    public java.sql.Timestamp getTimestamp(String name) {
1085
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(name, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
1086
        return value;
1087
    }
1088

    
1089
    @Override
1090
    public java.sql.Timestamp getTimestamp(int index) {
1091
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(index, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
1092
        return value;
1093
    }
1094

    
1095
    @Override
1096
    public double getDouble(String name) {
1097
        Double value = ((Double) this.get(name, Double.class, DataTypes.DOUBLE));
1098
        if (value == null) {
1099
            return 0;
1100
        }
1101
        return value;
1102
    }
1103

    
1104
    @Override
1105
    public double getDouble(int index) {
1106

    
1107
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
1108
        if (value == null) {
1109
            return 0;
1110
        }
1111
        return value;
1112
    }
1113

    
1114
    @Override
1115
    public BigDecimal getDecimal(String name) {
1116
        BigDecimal value = ((BigDecimal) this.get(name, BigDecimal.class, DataTypes.DECIMAL));
1117
        return value;
1118
    }
1119

    
1120
    @Override
1121
    public BigDecimal getDecimal(int index) {
1122
        BigDecimal value = ((BigDecimal) this.get(index, BigDecimal.class, DataTypes.DECIMAL));
1123
        return value;
1124
    }
1125

    
1126
    @Override
1127
    public Feature getFeature(String name) {
1128
        return this.getFeature(this.data.getType().getIndex(name));
1129
    }
1130

    
1131
    @Override
1132
    public Feature getFeature(int index) {
1133
        return (Feature) this.get(index);
1134
    }
1135

    
1136
    @Override
1137
    public float getFloat(String name) {
1138
        Float value = ((Float) this.get(name, Float.class, DataTypes.FLOAT));
1139
        if (value == null) {
1140
            return 0;
1141
        }
1142
        return value;
1143
    }
1144

    
1145
    @Override
1146
    public float getFloat(int index) {
1147
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1148
        if (value == null) {
1149
            return 0;
1150
        }
1151
        return value;
1152
    }
1153

    
1154
    @Override
1155
    public Geometry getGeometry(String name) {
1156
        return (Geometry) this.get(name, Geometry.class, DataTypes.GEOMETRY);
1157
    }
1158

    
1159
    @Override
1160
    public Geometry getGeometry(int index) {
1161
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1162
    }
1163

    
1164
    @Override
1165
    public int getInt(String name) {
1166
        Integer value = ((Integer) this.get(name, Integer.class, DataTypes.INT));
1167
        if (value == null) {
1168
            return 0;
1169
        }
1170
        return value;
1171
    }
1172

    
1173
    @Override
1174
    public int getInt(int index) {
1175
        Integer value = ((Integer) this.get(index, Integer.class, DataTypes.INT));
1176
        if (value == null) {
1177
            return 0;
1178
        }
1179
        return value;
1180
    }
1181

    
1182
    @Override
1183
    public long getLong(String name) {
1184
        Long value = ((Long) this.get(name, Long.class, DataTypes.LONG));
1185
        if (value == null) {
1186
            return 0;
1187
        }
1188
        return value;
1189
    }
1190

    
1191
    @Override
1192
    public long getLong(int index) {
1193
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1194
        if (value == null) {
1195
            return 0;
1196
        }
1197
        return value;
1198
    }
1199

    
1200
    @Override
1201
    public String getString(String name) {
1202
        return (String) this.get(name, String.class, DataTypes.STRING);
1203
    }
1204

    
1205
    @Override
1206
    public String getString(int index) {
1207
        return (String) this.get(index, String.class, DataTypes.STRING);
1208
    }
1209

    
1210
    @Override
1211
    public Object getContextValue(String name) {
1212
        name = name.toLowerCase();
1213
        if (name.equals("store")) {
1214
            return this.getStore();
1215
        }
1216

    
1217
        if (name.equals("featuretype")) {
1218
            return this.data.getType();
1219
        }
1220

    
1221
        if (name.equals("feature")) {
1222
            return this;
1223
        }
1224

    
1225
        throw new IllegalArgumentException(name);
1226
    }
1227

    
1228
    @Override
1229
    public Iterator getDataNames() {
1230
        class DataNamesIterator implements Iterator {
1231

    
1232
            Iterator attributeIteraror;
1233

    
1234
            DataNamesIterator(DefaultFeature feature) {
1235
                this.attributeIteraror = feature.getType().iterator();
1236
            }
1237

    
1238
            @Override
1239
            public boolean hasNext() {
1240
                return this.attributeIteraror.hasNext();
1241
            }
1242

    
1243
            @Override
1244
            public Object next() {
1245
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1246
                        .next()).getName();
1247
            }
1248

    
1249
            @Override
1250
            public void remove() {
1251
                throw new UnsupportedOperationException();
1252
            }
1253

    
1254
        }
1255
        return new DataNamesIterator(this);
1256
    }
1257

    
1258
    @Override
1259
    public Object getDataValue(String name) {
1260
        name = name.toLowerCase();
1261
        try {
1262
            return get(name);
1263
        } catch (IllegalArgumentException ex) {
1264
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1265
                return this.getDefaultGeometry();
1266
            }
1267
            throw ex;
1268
        }
1269
    }
1270

    
1271
    @Override
1272
    public Iterator getDataValues() {
1273
        class DataValuesIterator implements Iterator {
1274

    
1275
            DefaultFeature feature;
1276
            int current = 0;
1277

    
1278
            DataValuesIterator(DefaultFeature feature) {
1279
                this.feature = feature;
1280
            }
1281

    
1282
            @Override
1283
            public boolean hasNext() {
1284
                return current < feature.getType().size() - 1;
1285
            }
1286

    
1287
            @Override
1288
            public Object next() {
1289
                return feature.get(current++);
1290
            }
1291

    
1292
            @Override
1293
            public void remove() {
1294
                throw new UnsupportedOperationException();
1295
            }
1296

    
1297
        }
1298
        return new DataValuesIterator(this);
1299
    }
1300

    
1301
    @Override
1302
    public boolean hasContextValue(String name) {
1303
        name = name.toLowerCase();
1304
        if (name.equals("store")) {
1305
            return true;
1306
        }
1307

    
1308
        if (name.equals("featuretype")) {
1309
            return true;
1310
        }
1311

    
1312
        return name.equals("feature");
1313
    }
1314

    
1315
    @Override
1316
    public boolean hasDataValue(String name) {
1317
        return this.hasValue(name);
1318
    }
1319

    
1320
//    @Override
1321
//    public Time getTime(int index) {
1322
//        return ((Time) this.get(index,Time.class,DataTypes.INSTANT));
1323
//    }
1324
//
1325
//    @Override
1326
//    public Time getTime(String name) {
1327
//        return this.getInstant(this.data.getType().getIndex(name));
1328
//    }
1329
//
1330
//    @Override
1331
//    public Instant getInstant(int index) {
1332
//        return ((Instant) this.get(index,Instant.class,DataTypes.INSTANT));
1333
//    }
1334
//
1335
//    @Override
1336
//    public Instant getInstant(String name) {
1337
//        return this.getInstant(this.data.getType().getIndex(name));
1338
//    }
1339
//
1340
//    @Override
1341
//    public Interval getInterval(int index) {
1342
//        return ((Interval) this.get(index,Interval.class,DataTypes.INTERVAL));
1343
//    }
1344
//
1345
//    @Override
1346
//    public Interval getInterval(String name) {
1347
//        return this.getInterval(this.data.getType().getIndex(name));
1348
//    }
1349
//
1350
    @Override
1351
    public DynObject getAsDynObject() {
1352
        DynObjectFeatureFacade facade = new DynObjectFeatureFacade(this);
1353
        return facade;
1354
    }
1355

    
1356
    @Override
1357
    public String toString() {
1358
        StringBuilder builder = new StringBuilder();
1359
        FeatureAttributeDescriptor[] attributeDescriptors
1360
                = getType().getAttributeDescriptors();
1361
        for (int i = 0; i < attributeDescriptors.length; i++) {
1362
            String name = attributeDescriptors[i].getName();
1363
            Object value = get(name);
1364
            builder.append(value);
1365
            if (i < attributeDescriptors.length - 1) {
1366
                builder.append(", ");
1367
            }
1368
        }
1369
        return builder.toString();
1370
    }
1371

    
1372
    /**
1373
     * It is a new feature that has already been inserted into the store but has not yet been saved to disk
1374
     * 
1375
     * @return the inserted
1376
     */
1377
    public boolean isInserted() {
1378
        return inserted;
1379
    }
1380

    
1381
    /**
1382
     * If true, marks the feature as already inserted in the vault but has not yet been saved to disk
1383
     * 
1384
     * @param inserted the inserted to set
1385
     */
1386
    public void setInserted(boolean inserted) {
1387
        this.inserted = inserted;
1388
//        this.data.setNew(!inserted);
1389
    }
1390

    
1391
    @Override
1392
    public EvaluatorData getEvaluatorData() {
1393
        return this;
1394
    }
1395

    
1396
    @Override
1397
    public int size() {
1398
        return this.data.getType().size();
1399
    }
1400

    
1401
    public boolean isEmpty() {
1402
        return false;
1403
    }
1404

    
1405
    public Iterator<String> iterator() {
1406
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1407
        return new Iterator<String>() {
1408
            @Override
1409
            public boolean hasNext() {
1410
                return x.hasNext();
1411
            }
1412

    
1413
            @Override
1414
            public String next() {
1415
                return x.next().getName();
1416
            }
1417
        };
1418
    }
1419

    
1420
    public boolean containsKey(String key) {
1421
        return this.data.getType().get(key) != null;
1422
    }
1423

    
1424
    @Override
1425
    public String getLabelOfValue(String name) {
1426
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1427
        Object value;
1428
        if (attrdesc == null) { // extra column
1429
            FeatureExtraColumns extraColumns = this.data.getType().getExtraColumns();
1430
            if (extraColumns==null) {
1431
                return name;
1432
            }
1433
            attrdesc = extraColumns.get(name);
1434
            if(attrdesc==null) {
1435
                return name;
1436
            }
1437
           value = this.get(name);
1438
        } else {
1439
           value = this.get(attrdesc.getIndex());
1440
        }
1441
        String label;
1442
        try {
1443
            label = attrdesc.getLabelOfValue(value);
1444
        } catch(Throwable th) {
1445
            label = Objects.toString(value, "");
1446
        }
1447
        return label;
1448
    }
1449

    
1450
    @Override
1451
    public void setExtraValue(String name, Object value) {
1452
        if (this.extraValues == null) {
1453
            this.extraValues = new HashMap<>();
1454
        }
1455
        this.extraValues.put(name, value);
1456
    }
1457

    
1458
    public Object getExtraColumnValue(String name) {
1459
        Object value;
1460
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1461
        int index = columns.getIndexOf(name);
1462
        if (this.extraValues != null) {
1463
            if (this.extraValues.containsKey(name)) {
1464
                value = this.extraValues.get(name);
1465
                if (index >= 0){
1466
                    EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1467
                    value = coerce(attrdesc, value);
1468
                }
1469
                return value;
1470
            }
1471
        }
1472
        if (index < 0) {
1473
            throw new RuntimeException("Not extra column value found");
1474
        }
1475
        if (extraValuesData == null) {
1476
            extraValuesData = new Object[columns.size()];
1477
        }
1478
        EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1479
        value = extraValuesData[index];
1480
        if (value != null) {
1481
            return value;
1482
        }
1483
        value = this.getExtraValue(name);
1484
        if (value == null && !this.hasExtraValue(name) && attrdesc.getFeatureAttributeEmulator() != null) {
1485
            value = attrdesc.getFeatureAttributeEmulator().get(this);
1486
            value = coerce(attrdesc, value);
1487
            extraValuesData[index] = value;
1488
        } else {
1489
            value = coerce(attrdesc, value);
1490
            extraValuesData[index] = value;
1491
        }
1492
        
1493
        return value;
1494
    }
1495

    
1496
    @Override
1497
    public Object getExtraValue(String name) {
1498
        Object value = this.data.getExtraValue(name);
1499
        return value;
1500
    }
1501

    
1502
    @Override
1503
    public boolean hasExtraValue(String name) {
1504
        return this.data.hasExtraValue(name);
1505
    }
1506

    
1507
    private boolean hasExtraColumnValue(String name) {
1508
        if (this.extraValues != null) {
1509
            if (this.extraValues.containsKey(name)) {
1510
                return true;
1511
            }
1512
        }
1513
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1514
        int index = columns.getIndexOf(name);
1515
        if (index >= 0) {
1516
            return true;
1517
        }
1518
        return false;
1519
    }
1520

    
1521
    private EditableFeatureAttributeDescriptor getExtraColumn(String name) {
1522
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1523
        return columns.get(name);
1524
    }
1525

    
1526
    @Override
1527
    public boolean hasValue(String name) {
1528
        name = name.toLowerCase();
1529
        return this.data.getType().getIndex(name) >= 0
1530
                || hasExtraValue(name)
1531
                || hasExtraColumnValue(name);
1532
    }
1533

    
1534
    @Override
1535
    public Object getExtraValue(int index) {
1536
        return this.data.getExtraValue(index);
1537
    }
1538

    
1539
    @Override
1540
    public JsonObject toJson() {
1541
        JsonObjectBuilder builder = this.toJsonBuilder();
1542
        return builder.build();
1543
    }
1544
    
1545
    public JsonObject toJson(Map<String, Object> props) {
1546
        JsonObjectBuilder builder = this.toJsonBuilder(props);
1547
        return builder.build();
1548
    }
1549

    
1550
    @Override
1551
    public JsonObjectBuilder toJsonBuilder() {
1552
        return this.toJsonBuilder(null, Bitmask.createBitmask(TOJSON_MODE_SHALLOW), null);
1553
//        JsonObjectBuilder builder = Json.createObjectBuilder();
1554
//        Date date;
1555
//        Geometry geom;
1556
//        FeatureType ft = this.getType();
1557
//        for (FeatureAttributeDescriptor desc : ft) {
1558
//            if (desc.isComputed()) {
1559
//                continue;
1560
//            }
1561
//            if(this.isNull(desc.getName())){
1562
//                builder.addNull(desc.getName());
1563
//                continue;
1564
//            }
1565
//            switch (desc.getType()) {
1566
//                case DataTypes.GEOMETRY:
1567
//                    geom = this.getGeometry(desc.getIndex());
1568
//                    if (geom != null) {
1569
//                        builder.add(desc.getName(), geom.convertToHexWKBQuietly());
1570
//                    }
1571
//                    break;
1572
//                case DataTypes.BOOLEAN:
1573
//                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1574
//                    break;
1575
//                case DataTypes.BYTE:
1576
//                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1577
//                    break;
1578
//                case DataTypes.INT:
1579
//                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1580
//                    break;
1581
//                case DataTypes.LONG:
1582
//                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1583
//                    break;
1584
//                case DataTypes.DOUBLE:
1585
//                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1586
//                    break;
1587
//                case DataTypes.FLOAT:
1588
//                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1589
//                    break;
1590
//                case DataTypes.DECIMAL:
1591
//                    builder.add(desc.getName(), this.getDecimal(desc.getIndex()));
1592
//                    break;
1593
//                case DataTypes.DATE:
1594
//                    // Format date as ISO 8601
1595
//                    date = this.getDate(desc.getIndex());
1596
//                    if (date == null) {
1597
//                        builder.addNull(desc.getName());
1598
//                    } else {
1599
//                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1600
//                        String value = DateTimeFormatter.ISO_DATE.format(localDateTime);
1601
//                        builder.add(desc.getName(), value);
1602
//                    }
1603
//                    break;
1604
//                case DataTypes.TIMESTAMP:
1605
//                    // Format date as ISO 8601
1606
//                    date = this.getTimestamp(desc.getIndex());
1607
//                    if (date == null) {
1608
//                        builder.addNull(desc.getName());
1609
//                    } else {
1610
//                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1611
//                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1612
//                        builder.add(desc.getName(), value);
1613
//                    }
1614
//                    break;
1615
//                case DataTypes.TIME:
1616
//                    // Format date as ISO 8601
1617
//                    date = this.getTime(desc.getIndex());
1618
//                    if (date == null) {
1619
//                        builder.addNull(desc.getName());
1620
//                    } else {
1621
//                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1622
//                        String value = DateTimeFormatter.ISO_TIME.format(localDateTime);
1623
//                        builder.add(desc.getName(), value);
1624
//                    }
1625
//                    break;
1626
//                default:
1627
//                    builder.add(desc.getName(), this.getStringOrDefault(desc.getIndex(), ""));
1628
//            }
1629
//        }
1630
//        return builder;
1631
    }
1632

    
1633
    public static final String TOJSON_MODE = "mode";
1634
    public static final int TOJSON_MODE_SHALLOW = 0;
1635
    public static final int TOJSON_MODE_DEEP =        0b00001;
1636
    public static final int TOJSON_MODE_COMPUTEDS =   0b00010;
1637
    public static final int TOJSON_MODE_COLLECTIONS = 0b00100;
1638
    
1639
    @Override
1640
    public JsonObjectBuilder toJsonBuilder(Map<String, Object> props) {    
1641
        Bitmask modemask = null;
1642
        Set<String> visiteds = null;
1643
        int mode = TOJSON_MODE_SHALLOW;
1644
        if( props!=null ) {
1645
            mode = (int) props.getOrDefault(TOJSON_MODE,mode);
1646
            modemask = Bitmask.createBitmask(mode);
1647
            if( modemask.isSetBits(TOJSON_MODE_DEEP) ) {
1648
                visiteds = (Set<String>) props.getOrDefault("visiteds", null);
1649
                if( visiteds == null ) {
1650
                    visiteds = new HashSet<>();
1651
                    props.put("visiteds", visiteds);
1652
                }
1653
            }
1654
        } else {
1655
            modemask = Bitmask.createBitmask(mode);
1656
        }
1657
        return this.toJsonBuilder(props, modemask, visiteds);
1658
    }
1659
    
1660
    private JsonObjectBuilder toJsonBuilder(Map<String, Object> props, Bitmask mode, Set<String> visiteds) {    
1661
        JsonObjectBuilder builder = Json.createObjectBuilder();
1662
        Date date;
1663
        Geometry geom;
1664
        FeatureType ft = this.getType();
1665
        
1666
        boolean hasVisited = false;
1667
        if(visiteds != null){
1668
            FeatureReference ref = this.getReference();
1669
            String code = ref.getCode();
1670
            hasVisited = visiteds.contains(code);
1671
            if(hasVisited){
1672
               return this.featureReferenceToJson(ref);
1673
            }
1674
            visiteds.add(code);
1675
        }
1676
        
1677
        for (FeatureAttributeDescriptor desc : ft) {
1678
            if (desc.isComputed() ) { 
1679
                if( !mode.isSetBits(TOJSON_MODE_COMPUTEDS) ) {
1680
                    if( !(mode.isSetBits(TOJSON_MODE_COLLECTIONS) && desc.getType()==DataTypes.LIST) ) { 
1681
                        continue;
1682
                    }
1683
                }
1684
            }
1685
            if(desc.getType() != DataTypes.LIST && this.isNull(desc.getName()) ){
1686
                builder.addNull(desc.getName());
1687
                continue;
1688
            }
1689
            if( desc.isForeingKey() && !desc.getForeingKey().isClosedList() && mode.isSetBits(TOJSON_MODE_DEEP) ) {
1690
                if( desc.getRelationType()==DynField.RELATION_TYPE_COLLABORATION_WITH_COMPOSITION) {
1691
                    Object value = this.get(desc.getName());
1692
                    if(value != null){
1693
                        Feature f = desc.getForeingKey().getFeature(null, value);
1694
                        if(f!=null){ //Ojo, si no hay constraint no tendria porque ser un error que no se encontrara la feature
1695
                            String x = f.getReference().getCode();
1696
                            if( visiteds==null ) {
1697
                                if( f instanceof DefaultFeature ) {
1698
                                    builder.add(desc.getName(), ((DefaultFeature)f).toJsonBuilder(props, mode, visiteds));
1699
                                } else {
1700
                                    builder.add(desc.getName(), f.toJsonBuilder(props));
1701
                                }
1702
                                continue;
1703
                            } else if( !visiteds.contains(x) ) {
1704
                                if( f instanceof DefaultFeature ) {
1705
                                    builder.add(desc.getName(), ((DefaultFeature)f).toJsonBuilder(props, mode, visiteds));
1706
                                } else {
1707
                                    builder.add(desc.getName(), f.toJsonBuilder(props));
1708
                                }
1709
                                continue;
1710
                            }                           
1711
                        }
1712
                    }
1713
                }
1714
            }
1715
            switch (desc.getType()) {
1716
                case DataTypes.GEOMETRY:
1717
                    geom = this.getGeometry(desc.getIndex());
1718
                    if (geom != null) {
1719
                        builder.add(desc.getName(), geom.convertToHexWKBQuietly());
1720
                    }
1721
                    break;
1722
                case DataTypes.BOOLEAN:
1723
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1724
                    break;
1725
                case DataTypes.BYTE:
1726
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1727
                    break;
1728
                case DataTypes.INT:
1729
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1730
                    break;
1731
                case DataTypes.LONG:
1732
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1733
                    break;
1734
                case DataTypes.DOUBLE:
1735
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1736
                    break;
1737
                case DataTypes.FLOAT:
1738
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1739
                    break;
1740
                case DataTypes.DECIMAL:
1741
                    builder.add(desc.getName(), this.getDecimal(desc.getIndex()));
1742
                    break;
1743
                case DataTypes.DATE:
1744
                    // Format date as ISO 8601
1745
                    date = this.getDate(desc.getIndex());
1746
                    if (date == null) {
1747
                        builder.addNull(desc.getName());
1748
                    } else {
1749
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1750
                        String value = DateTimeFormatter.ISO_DATE.format(localDateTime);
1751
                        builder.add(desc.getName(), value);
1752
                    }
1753
                    break;
1754
                case DataTypes.TIMESTAMP:
1755
                    // Format date as ISO 8601
1756
                    date = this.getTimestamp(desc.getIndex());
1757
                    if (date == null) {
1758
                        builder.addNull(desc.getName());
1759
                    } else {
1760
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1761
                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1762
                        builder.add(desc.getName(), value);
1763
                    }
1764
                    break;
1765
                case DataTypes.TIME:
1766
                    // Format date as ISO 8601
1767
                    date = this.getTime(desc.getIndex());
1768
                    if (date == null) {
1769
                        builder.addNull(desc.getName());
1770
                    } else {
1771
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1772
                        String value = DateTimeFormatter.ISO_TIME.format(localDateTime);
1773
                        builder.add(desc.getName(), value);
1774
                    }
1775
                    break;
1776
                case DataTypes.LIST: 
1777
                    if( mode.isSetBits(TOJSON_MODE_COLLECTIONS) ) {
1778
                        if( desc.getRelationType()== DynField.RELATION_TYPE_AGGREGATE_WITH_COMPOSITION) {
1779
                            JsonArrayBuilder arraybuilder = Json.createArrayBuilder();
1780
                            Object x = this.get(desc.getName());
1781
                            if( x instanceof List ) {
1782
                                for (Object v : (List)x) {
1783
                                    if( v instanceof DefaultFeature ) {
1784
                                            arraybuilder.add(((DefaultFeature)v).toJsonBuilder(props, mode, visiteds));
1785
                                    } else if( v instanceof Feature ) {
1786
                                        arraybuilder.add(((Feature)v).toJsonBuilder(props));
1787
                                    }
1788
                                }
1789
                            }
1790
                            DisposeUtils.disposeQuietly(x);
1791
                            builder.add(desc.getName(), arraybuilder);
1792
                        }
1793
                    }
1794
                    break;
1795
                    
1796
                default:
1797
                    builder.add(desc.getName(), this.getStringOrDefault(desc.getIndex(), ""));
1798
            }
1799
        }
1800
        return builder;
1801
    }
1802
    
1803
    private JsonObjectBuilder featureReferenceToJson(FeatureReference ref){
1804
        JsonObjectBuilder builder = Json.createObjectBuilder();
1805
        builder.add("$reference", ref.toJsonBuilder());
1806
        return builder;
1807
    }
1808

    
1809
    @Override
1810
    public List<String> getKeys() {
1811
        List<String> l = new ArrayList<>();
1812
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1813
            l.add(descriptor.getName());
1814
        }
1815
        return l;
1816
    }
1817

    
1818
    @Override
1819
    public String format(String name) {
1820
        int index = this.data.getType().getIndex(name);
1821
        if (index < 0) {
1822
            // buscamos en los extra cols
1823
            FeatureAttributeDescriptor attribute = this.getExtraColumn(name);
1824
            if( attribute!=null ) {
1825
                Object value = getExtraColumnValue(name);
1826
                return attribute.format(value);
1827
            }
1828
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1829
        }
1830
        return this.format(index);
1831
    }
1832

    
1833
    @Override
1834
    public String format(int index) {
1835
        Object value = this.get(index);
1836
        FeatureType type = this.data.getType();
1837
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
1838
        return attribute.format(value);
1839
    }
1840
    
1841
    @Override
1842
    public Feature getForeignFeature(String attrName) {
1843
        ForeingKey.ContextForeingKey context = null;
1844
        try {
1845
            FeatureAttributeDescriptor attr = this.getType().getAttributeDescriptor(attrName);
1846
            if (attr == null) {
1847
                return null;
1848
            }
1849
            if (!attr.isForeingKey()) {
1850
                return null;
1851
            }
1852
            ForeingKey fk = attr.getForeingKey();
1853
            if(fk == null){
1854
                return null;
1855
            }
1856
            context = fk.createContext();
1857
            FeatureStore store = this.getStore();
1858
            if(store instanceof SupportTransactions){
1859
                context.setTransaction(((SupportTransactions) store).getTransaction());
1860
            }
1861
            Feature foreignfeat = fk.getFeature(context, this.get(attrName));
1862
            return foreignfeat;
1863
        } catch (Exception ex) {
1864
            return null;
1865
        } finally {
1866
            DisposeUtils.disposeQuietly(context);
1867
        }
1868
    }
1869

    
1870

    
1871
    @Override
1872
    public Expression createFilter() {
1873
        FeatureType ftype = this.getType();
1874
        FeatureAttributeDescriptor[] pk = ftype.getPrimaryKey();
1875
        if( ArrayUtils.isEmpty(pk) ) {
1876
            return null;
1877
        }
1878
        ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
1879
        for (FeatureAttributeDescriptor attrdesc : pk) {
1880
            Object value = this.get(attrdesc.getName());
1881
            if( value == null ) {
1882
                builder.and(
1883
                        builder.is_null(builder.column(attrdesc.getName()))
1884
                );
1885
            } else {
1886
                builder.and(
1887
                        builder.eq(
1888
                                builder.column(attrdesc.getName()),
1889
                                builder.constant(value)
1890
                        )
1891
                );
1892
            }
1893
        }
1894
        Expression filter = ExpressionUtils.createExpression(builder.toString());                            
1895
        return filter;
1896
    }
1897
}