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

History | View | Annotate | Download (64.4 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.dynobject.Tags;
88
import org.gvsig.tools.evaluator.Evaluator;
89
import org.gvsig.tools.evaluator.EvaluatorData;
90
import org.gvsig.tools.evaluator.EvaluatorException;
91
import org.gvsig.tools.exception.BaseException;
92
import org.gvsig.tools.exception.BaseRuntimeException;
93
import org.gvsig.tools.lang.Cloneable;
94
import org.gvsig.tools.util.Bitmask;
95
import org.slf4j.Logger;
96
import org.slf4j.LoggerFactory;
97

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

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

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

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

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

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

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

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

    
145
        FeatureType sourceType = sourceFeature.getType();
146

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

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

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

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

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

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

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

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

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

    
229
        }
230

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
665
    @Override
666
    public boolean isBroken() {
667
        return this.data.isBroken();
668
    }
669

    
670
    class UnableToGetReferenceException extends BaseRuntimeException {
671

    
672
        /**
673
         *
674
         */
675
        private static final long serialVersionUID = 1812805035204824163L;
676

    
677
        /**
678
         * @param exception
679
         */
680
        @SuppressWarnings("OverridableMethodCallInConstructor")
681
        public UnableToGetReferenceException(BaseException exception) {
682
            super("Unable to get reference", "_UnableToGetReferenceException",
683
                    serialVersionUID);
684
            this.initCause(exception);
685

    
686
        }
687

    
688
    }
689

    
690
    @Override
691
    public List getSRSs() {
692
        // TODO Auto-generated method stub
693
        return null;
694
    }
695

    
696
    @Override
697
    public Envelope getDefaultEnvelope() {
698
        Envelope envelope = this.data.getDefaultEnvelope();
699
        if (envelope == null) {
700
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
701
            if (i < 0) {
702
                return null;
703
            }
704
            Geometry geom = this.getDefaultGeometry();
705
            if (geom != null) {
706
                envelope = geom.getEnvelope();
707
            }
708
        }
709
        return envelope;
710
    }
711

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

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

    
764
    @Override
765
    public List getGeometries() {
766
        // TODO Auto-generated method stub
767
        return null;
768
    }
769

    
770
    @Override
771
    public Object getFromProfile(int index) {
772
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
773
        Object value = this.get(index);
774
        String profileName = descriptor.getDataProfileName();
775
        if (StringUtils.isBlank(profileName)) {
776
            return value;
777
        }
778
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
779
        if (profile == null) {
780
            return value;
781
        }
782
        return profile.createData(value, descriptor.getTags());
783
    }
784

    
785
    @Override
786
    public Object getFromProfile(String name) {
787
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
788
        return this.getFromProfile(descriptor.getIndex());
789
    }
790

    
791
    private Object get(String name, Class theClass, int type) {
792
        Object value = this.get(name);
793
        if (theClass.isInstance(value)) {
794
            return value;
795
        }
796
        try {
797
            return this.getDataTypesManager().coerce(type, value);
798
        } catch (CoercionException e) {
799

    
800
            if (value == null) {
801
                return null;
802
            }
803
            throw new IllegalArgumentException(
804
                    "Can't convert to " + theClass.getName()
805
                    + " from '" + value.getClass().getName()
806
                    + "' with value '" + value.toString() + "'.");
807
        }
808
    }
809

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

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

    
854
    @Override
855
    public boolean isNull(String name) {
856
        int index = this.data.getType().getIndex(name);
857
        if (index < 0) {
858
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
859
        }
860
        return this.isNull(index);
861
    }
862

    
863
    public boolean has_key(String key) {
864
        Object x = this.getType().get(key);
865
        return x != null;
866
    }
867

    
868
    public List<String> keys() {
869
        List<String> ks = new ArrayList<>();
870
        for (FeatureAttributeDescriptor attr : this.getType()) {
871
            ks.add(attr.getName());
872
        }
873
        return ks;
874
    }
875

    
876
    public Iterator<String> iterkeys() {
877
        final Iterator it = this.getType().iterator();
878
        return new Iterator<String>() {
879
            @Override
880
            public boolean hasNext() {
881
                return it.hasNext();
882
            }
883

    
884
            @Override
885
            public String next() {
886
                return ((FeatureAttributeDescriptor) it.next()).getName();
887
            }
888

    
889
            @Override
890
            public void remove() {
891
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
892
            }
893
        };
894
    }
895

    
896
    public Iterator iteritems() {
897
        final Iterator it = this.getType().iterator();
898
        return new Iterator<Map.Entry>() {
899
            @Override
900
            public boolean hasNext() {
901
                return it.hasNext();
902
            }
903

    
904
            @Override
905
            public Map.Entry next() {
906
                final String name = ((FeatureAttributeDescriptor) it.next()).getName();
907
                return new Map.Entry<String, Object>() {
908
                    @Override
909
                    public String getKey() {
910
                        return name;
911
                    }
912

    
913
                    @Override
914
                    public Object getValue() {
915
                        return get(name);
916
                    }
917

    
918
                    @Override
919
                    public Object setValue(Object value) {
920
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
921
                    }
922

    
923
                };
924
            }
925

    
926
            @Override
927
            public void remove() {
928
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
929
            }
930
        };
931
    }
932

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

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

    
1009
    @Override
1010
    public byte[] getByteArray(String name) {
1011
        return (byte[]) this.get(name);
1012
    }
1013

    
1014
    @Override
1015
    public byte[] getByteArray(int index) {
1016
        return (byte[]) this.get(index);
1017
    }
1018

    
1019
    @Override
1020
    public Object[] getArray(String name) {
1021
        return (Object[]) this.get(name);
1022
    }
1023

    
1024
    @Override
1025
    public Object[] getArray(int index) {
1026
        return (Object[]) this.get(index);
1027
    }
1028

    
1029
    @Override
1030
    public boolean getBoolean(String name) {
1031
        Boolean value = ((Boolean) this.get(name, Boolean.class, DataTypes.BOOLEAN));
1032
        if (value == null) {
1033
            return false;
1034
        }
1035
        return value;
1036
    }
1037

    
1038
    @Override
1039
    public boolean getBoolean(int index) {
1040
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
1041
        if (value == null) {
1042
            return false;
1043
        }
1044
        return value;
1045
    }
1046

    
1047
    @Override
1048
    public byte getByte(String name) {
1049
        Byte value = ((Byte) this.get(name, Byte.class, DataTypes.BYTE));
1050
        if (value == null) {
1051
            return 0;
1052
        }
1053
        return value;
1054
    }
1055

    
1056
    @Override
1057
    public byte getByte(int index) {
1058
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
1059
        if (value == null) {
1060
            return 0;
1061
        }
1062
        return value;
1063
    }
1064

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

    
1071
    @Override
1072
    public java.sql.Date getDate(int index) {
1073
        java.sql.Date value = ((java.sql.Date) this.get(index, java.sql.Date.class, DataTypes.DATE));
1074
        return value;
1075
    }
1076

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

    
1083
    @Override
1084
    public java.sql.Time getTime(int index) {
1085
        java.sql.Time value = ((java.sql.Time) this.get(index, java.sql.Time.class, DataTypes.TIME));
1086
        return value;
1087
    }
1088

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

    
1095
    @Override
1096
    public java.sql.Timestamp getTimestamp(int index) {
1097
        java.sql.Timestamp value = ((java.sql.Timestamp) this.get(index, java.sql.Timestamp.class, DataTypes.TIMESTAMP));
1098
        return value;
1099
    }
1100

    
1101
    @Override
1102
    public double getDouble(String name) {
1103
        Double value = ((Double) this.get(name, Double.class, DataTypes.DOUBLE));
1104
        if (value == null) {
1105
            return 0;
1106
        }
1107
        return value;
1108
    }
1109

    
1110
    @Override
1111
    public double getDouble(int index) {
1112

    
1113
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
1114
        if (value == null) {
1115
            return 0;
1116
        }
1117
        return value;
1118
    }
1119

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

    
1126
    @Override
1127
    public BigDecimal getDecimal(int index) {
1128
        BigDecimal value = ((BigDecimal) this.get(index, BigDecimal.class, DataTypes.DECIMAL));
1129
        return value;
1130
    }
1131

    
1132
    @Override
1133
    public Feature getFeature(String name) {
1134
        return this.getFeature(this.data.getType().getIndex(name));
1135
    }
1136

    
1137
    @Override
1138
    public Feature getFeature(int index) {
1139
        return (Feature) this.get(index);
1140
    }
1141

    
1142
    @Override
1143
    public float getFloat(String name) {
1144
        Float value = ((Float) this.get(name, Float.class, DataTypes.FLOAT));
1145
        if (value == null) {
1146
            return 0;
1147
        }
1148
        return value;
1149
    }
1150

    
1151
    @Override
1152
    public float getFloat(int index) {
1153
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1154
        if (value == null) {
1155
            return 0;
1156
        }
1157
        return value;
1158
    }
1159

    
1160
    @Override
1161
    public Geometry getGeometry(String name) {
1162
        return (Geometry) this.get(name, Geometry.class, DataTypes.GEOMETRY);
1163
    }
1164

    
1165
    @Override
1166
    public Geometry getGeometry(int index) {
1167
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1168
    }
1169

    
1170
    @Override
1171
    public int getInt(String name) {
1172
        Integer value = ((Integer) this.get(name, Integer.class, DataTypes.INT));
1173
        if (value == null) {
1174
            return 0;
1175
        }
1176
        return value;
1177
    }
1178

    
1179
    @Override
1180
    public int getInt(int index) {
1181
        Integer value = ((Integer) this.get(index, Integer.class, DataTypes.INT));
1182
        if (value == null) {
1183
            return 0;
1184
        }
1185
        return value;
1186
    }
1187

    
1188
    @Override
1189
    public long getLong(String name) {
1190
        Long value = ((Long) this.get(name, Long.class, DataTypes.LONG));
1191
        if (value == null) {
1192
            return 0;
1193
        }
1194
        return value;
1195
    }
1196

    
1197
    @Override
1198
    public long getLong(int index) {
1199
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1200
        if (value == null) {
1201
            return 0;
1202
        }
1203
        return value;
1204
    }
1205

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

    
1211
    @Override
1212
    public String getString(int index) {
1213
        return (String) this.get(index, String.class, DataTypes.STRING);
1214
    }
1215

    
1216
    @Override
1217
    public Object getContextValue(String name) {
1218
        name = name.toLowerCase();
1219
        if (name.equals("store")) {
1220
            return this.getStore();
1221
        }
1222

    
1223
        if (name.equals("featuretype")) {
1224
            return this.data.getType();
1225
        }
1226

    
1227
        if (name.equals("feature")) {
1228
            return this;
1229
        }
1230

    
1231
        throw new IllegalArgumentException(name);
1232
    }
1233

    
1234
    @Override
1235
    public Iterator getDataNames() {
1236
        class DataNamesIterator implements Iterator {
1237

    
1238
            Iterator attributeIteraror;
1239

    
1240
            DataNamesIterator(DefaultFeature feature) {
1241
                this.attributeIteraror = feature.getType().iterator();
1242
            }
1243

    
1244
            @Override
1245
            public boolean hasNext() {
1246
                return this.attributeIteraror.hasNext();
1247
            }
1248

    
1249
            @Override
1250
            public Object next() {
1251
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1252
                        .next()).getName();
1253
            }
1254

    
1255
            @Override
1256
            public void remove() {
1257
                throw new UnsupportedOperationException();
1258
            }
1259

    
1260
        }
1261
        return new DataNamesIterator(this);
1262
    }
1263

    
1264
    @Override
1265
    public Object getDataValue(String name) {
1266
        name = name.toLowerCase();
1267
        try {
1268
            return get(name);
1269
        } catch (IllegalArgumentException ex) {
1270
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1271
                return this.getDefaultGeometry();
1272
            }
1273
            throw ex;
1274
        }
1275
    }
1276

    
1277
    @Override
1278
    public Iterator getDataValues() {
1279
        class DataValuesIterator implements Iterator {
1280

    
1281
            DefaultFeature feature;
1282
            int current = 0;
1283

    
1284
            DataValuesIterator(DefaultFeature feature) {
1285
                this.feature = feature;
1286
            }
1287

    
1288
            @Override
1289
            public boolean hasNext() {
1290
                return current < feature.getType().size() - 1;
1291
            }
1292

    
1293
            @Override
1294
            public Object next() {
1295
                return feature.get(current++);
1296
            }
1297

    
1298
            @Override
1299
            public void remove() {
1300
                throw new UnsupportedOperationException();
1301
            }
1302

    
1303
        }
1304
        return new DataValuesIterator(this);
1305
    }
1306

    
1307
    @Override
1308
    public boolean hasContextValue(String name) {
1309
        name = name.toLowerCase();
1310
        if (name.equals("store")) {
1311
            return true;
1312
        }
1313

    
1314
        if (name.equals("featuretype")) {
1315
            return true;
1316
        }
1317

    
1318
        return name.equals("feature");
1319
    }
1320

    
1321
    @Override
1322
    public boolean hasDataValue(String name) {
1323
        return this.hasValue(name);
1324
    }
1325

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

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

    
1378
    /**
1379
     * It is a new feature that has already been inserted into the store but has not yet been saved to disk
1380
     * 
1381
     * @return the inserted
1382
     */
1383
    public boolean isInserted() {
1384
        return inserted;
1385
    }
1386

    
1387
    /**
1388
     * If true, marks the feature as already inserted in the vault but has not yet been saved to disk
1389
     * 
1390
     * @param inserted the inserted to set
1391
     */
1392
    public void setInserted(boolean inserted) {
1393
        this.inserted = inserted;
1394
//        this.data.setNew(!inserted);
1395
    }
1396

    
1397
    @Override
1398
    public EvaluatorData getEvaluatorData() {
1399
        return this;
1400
    }
1401

    
1402
    @Override
1403
    public int size() {
1404
        return this.data.getType().size();
1405
    }
1406

    
1407
    public boolean isEmpty() {
1408
        return false;
1409
    }
1410

    
1411
    public Iterator<String> iterator() {
1412
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1413
        return new Iterator<String>() {
1414
            @Override
1415
            public boolean hasNext() {
1416
                return x.hasNext();
1417
            }
1418

    
1419
            @Override
1420
            public String next() {
1421
                return x.next().getName();
1422
            }
1423
        };
1424
    }
1425

    
1426
    public boolean containsKey(String key) {
1427
        return this.data.getType().get(key) != null;
1428
    }
1429

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

    
1456
    @Override
1457
    public void setExtraValue(String name, Object value) {
1458
        if (this.extraValues == null) {
1459
            this.extraValues = new HashMap<>();
1460
        }
1461
        this.extraValues.put(name, value);
1462
    }
1463

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

    
1502
    @Override
1503
    public Object getExtraValue(String name) {
1504
        Object value = this.data.getExtraValue(name);
1505
        return value;
1506
    }
1507

    
1508
    @Override
1509
    public boolean hasExtraValue(String name) {
1510
        return this.data.hasExtraValue(name);
1511
    }
1512

    
1513
    private boolean hasExtraColumnValue(String name) {
1514
        if (this.extraValues != null) {
1515
            if (this.extraValues.containsKey(name)) {
1516
                return true;
1517
            }
1518
        }
1519
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1520
        int index = columns.getIndexOf(name);
1521
        if (index >= 0) {
1522
            return true;
1523
        }
1524
        return false;
1525
    }
1526

    
1527
    private EditableFeatureAttributeDescriptor getExtraColumn(String name) {
1528
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1529
        return columns.get(name);
1530
    }
1531

    
1532
    @Override
1533
    public boolean hasValue(String name) {
1534
        name = name.toLowerCase();
1535
        return this.data.getType().getIndex(name) >= 0
1536
                || hasExtraValue(name)
1537
                || hasExtraColumnValue(name);
1538
    }
1539

    
1540
    @Override
1541
    public Object getExtraValue(int index) {
1542
        return this.data.getExtraValue(index);
1543
    }
1544

    
1545
    @Override
1546
    public JsonObject toJson() {
1547
        JsonObjectBuilder builder = this.toJsonBuilder();
1548
        return builder.build();
1549
    }
1550
    
1551
    public JsonObject toJson(Map<String, Object> props) {
1552
        JsonObjectBuilder builder = this.toJsonBuilder(props);
1553
        return builder.build();
1554
    }
1555

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

    
1639
    public static final String TOJSON_MODE = "mode";
1640
    public static final int TOJSON_MODE_SHALLOW = 0;
1641
    public static final int TOJSON_MODE_DEEP =        0b00001;
1642
    public static final int TOJSON_MODE_COMPUTEDS =   0b00010;
1643
    public static final int TOJSON_MODE_COLLECTIONS = 0b00100;
1644
    
1645
    @Override
1646
    public JsonObjectBuilder toJsonBuilder(Map<String, Object> props) {    
1647
        Bitmask modemask = null;
1648
        Set<String> visiteds = null;
1649
        int mode = TOJSON_MODE_SHALLOW;
1650
        if( props!=null ) {
1651
            mode = (int) props.getOrDefault(TOJSON_MODE,mode);
1652
            modemask = Bitmask.createBitmask(mode);
1653
            if( modemask.isSetBits(TOJSON_MODE_DEEP) ) {
1654
                visiteds = (Set<String>) props.getOrDefault("visiteds", null);
1655
                if( visiteds == null ) {
1656
                    visiteds = new HashSet<>();
1657
                    props.put("visiteds", visiteds);
1658
                }
1659
            }
1660
        } else {
1661
            modemask = Bitmask.createBitmask(mode);
1662
        }
1663
        return this.toJsonBuilder(props, modemask, visiteds);
1664
    }
1665
    
1666
    private JsonObjectBuilder toJsonBuilder(Map<String, Object> props, Bitmask mode, Set<String> visiteds) {    
1667
        JsonObjectBuilder builder = Json.createObjectBuilder();
1668
        Date date;
1669
        Geometry geom;
1670
        FeatureType ft = this.getType();
1671
        
1672
        boolean hasVisited = false;
1673
        if(visiteds != null){
1674
            FeatureReference ref = this.getReference();
1675
            String code = ref.getCode();
1676
            hasVisited = visiteds.contains(code);
1677
            if(hasVisited){
1678
               return this.featureReferenceToJson(ref);
1679
            }
1680
            visiteds.add(code);
1681
        }
1682
        
1683
        for (FeatureAttributeDescriptor desc : ft) {
1684
            if (desc.isComputed() ) { 
1685
                if( !mode.isSetBits(TOJSON_MODE_COMPUTEDS) ) {
1686
                    if( !(mode.isSetBits(TOJSON_MODE_COLLECTIONS) && desc.getType()==DataTypes.LIST) ) { 
1687
                        continue;
1688
                    }
1689
                }
1690
            }
1691
            if(desc.getType() != DataTypes.LIST && this.isNull(desc.getName()) ){
1692
                builder.addNull(desc.getName());
1693
                continue;
1694
            }
1695
            if( desc.isForeingKey() && !desc.getForeingKey().isClosedList() && mode.isSetBits(TOJSON_MODE_DEEP) ) {
1696
                if( desc.getRelationType()==DynField.RELATION_TYPE_COLLABORATION_WITH_COMPOSITION) {
1697
                    Object value = this.get(desc.getName());
1698
                    if(value != null){
1699
                        Feature f = desc.getForeingKey().getFeature(null, value);
1700
                        if(f!=null){ //Ojo, si no hay constraint no tendria porque ser un error que no se encontrara la feature
1701
                            String x = f.getReference().getCode();
1702
                            if( visiteds==null ) {
1703
                                if( f instanceof DefaultFeature ) {
1704
                                    builder.add(desc.getName(), ((DefaultFeature)f).toJsonBuilder(props, mode, visiteds));
1705
                                } else {
1706
                                    builder.add(desc.getName(), f.toJsonBuilder(props));
1707
                                }
1708
                                continue;
1709
                            } else if( !visiteds.contains(x) ) {
1710
                                if( f instanceof DefaultFeature ) {
1711
                                    builder.add(desc.getName(), ((DefaultFeature)f).toJsonBuilder(props, mode, visiteds));
1712
                                } else {
1713
                                    builder.add(desc.getName(), f.toJsonBuilder(props));
1714
                                }
1715
                                continue;
1716
                            }                           
1717
                        }
1718
                    }
1719
                }
1720
            }
1721
            switch (desc.getType()) {
1722
                case DataTypes.GEOMETRY:
1723
                    geom = this.getGeometry(desc.getIndex());
1724
                    if (geom != null) {
1725
                        geom = this.getGeometry(desc.getIndex());
1726
                        Tags tags = desc.getTags();
1727
                        switch(tags.getString("geomformat", "WKB").toUpperCase()) {
1728
                            default:
1729
                            case "WKB":
1730
                            case "HEXWKB":
1731
                                builder.add(desc.getName(), geom.convertToHexWKBQuietly());
1732
                                break;
1733
                            case "EWKB":
1734
                            case "HEXEWKB":
1735
                                builder.add(desc.getName(), geom.convertToHexEWKBQuietly());
1736
                                break;
1737
                            case "WKT":
1738
                                builder.add(desc.getName(), geom.convertToWKTQuietly());
1739
                                break;
1740
                        }
1741
                    }
1742
                    break;
1743

    
1744
                case DataTypes.BOOLEAN:
1745
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1746
                    break;
1747
                case DataTypes.BYTE:
1748
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1749
                    break;
1750
                case DataTypes.INT:
1751
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1752
                    break;
1753
                case DataTypes.LONG:
1754
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1755
                    break;
1756
                case DataTypes.DOUBLE:
1757
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1758
                    break;
1759
                case DataTypes.FLOAT:
1760
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1761
                    break;
1762
                case DataTypes.DECIMAL:
1763
                    builder.add(desc.getName(), this.getDecimal(desc.getIndex()));
1764
                    break;
1765
                case DataTypes.DATE:
1766
                    // Format date as ISO 8601
1767
                    date = this.getDate(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_DATE.format(localDateTime);
1773
                        builder.add(desc.getName(), value);
1774
                    }
1775
                    break;
1776
                case DataTypes.TIMESTAMP:
1777
                    // Format date as ISO 8601
1778
                    date = this.getTimestamp(desc.getIndex());
1779
                    if (date == null) {
1780
                        builder.addNull(desc.getName());
1781
                    } else {
1782
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1783
                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1784
                        builder.add(desc.getName(), value);
1785
                    }
1786
                    break;
1787
                case DataTypes.TIME:
1788
                    // Format date as ISO 8601
1789
                    date = this.getTime(desc.getIndex());
1790
                    if (date == null) {
1791
                        builder.addNull(desc.getName());
1792
                    } else {
1793
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1794
                        String value = DateTimeFormatter.ISO_TIME.format(localDateTime);
1795
                        builder.add(desc.getName(), value);
1796
                    }
1797
                    break;
1798
                case DataTypes.LIST: 
1799
                    if( mode.isSetBits(TOJSON_MODE_COLLECTIONS) ) {
1800
                        if( desc.getRelationType()== DynField.RELATION_TYPE_AGGREGATE_WITH_COMPOSITION) {
1801
                            JsonArrayBuilder arraybuilder = Json.createArrayBuilder();
1802
                            Object x = this.get(desc.getName());
1803
                            if( x instanceof List ) {
1804
                                for (Object v : (List)x) {
1805
                                    if( v instanceof DefaultFeature ) {
1806
                                            arraybuilder.add(((DefaultFeature)v).toJsonBuilder(props, mode, visiteds));
1807
                                    } else if( v instanceof Feature ) {
1808
                                        arraybuilder.add(((Feature)v).toJsonBuilder(props));
1809
                                    }
1810
                                }
1811
                            }
1812
                            DisposeUtils.disposeQuietly(x);
1813
                            builder.add(desc.getName(), arraybuilder);
1814
                        }
1815
                    }
1816
                    break;
1817
                    
1818
                default:
1819
                    builder.add(desc.getName(), this.getStringOrDefault(desc.getIndex(), ""));
1820
            }
1821
        }
1822
        return builder;
1823
    }
1824
    
1825
    private JsonObjectBuilder featureReferenceToJson(FeatureReference ref){
1826
        JsonObjectBuilder builder = Json.createObjectBuilder();
1827
        builder.add("$reference", ref.toJsonBuilder());
1828
        return builder;
1829
    }
1830

    
1831
    @Override
1832
    public List<String> getKeys() {
1833
        List<String> l = new ArrayList<>();
1834
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1835
            l.add(descriptor.getName());
1836
        }
1837
        return l;
1838
    }
1839

    
1840
    @Override
1841
    public String format(String name) {
1842
        int index = this.data.getType().getIndex(name);
1843
        if (index < 0) {
1844
            // buscamos en los extra cols
1845
            FeatureAttributeDescriptor attribute = this.getExtraColumn(name);
1846
            if( attribute!=null ) {
1847
                Object value = getExtraColumnValue(name);
1848
                return attribute.format(value);
1849
            }
1850
            throw new IllegalArgumentException("Attribute name '" + name + "' not found in the feature.");
1851
        }
1852
        return this.format(index);
1853
    }
1854

    
1855
    @Override
1856
    public String format(int index) {
1857
        Object value = this.get(index);
1858
        FeatureType type = this.data.getType();
1859
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
1860
        return attribute.format(value);
1861
    }
1862
    
1863
    @Override
1864
    public Feature getForeignFeature(String attrName) {
1865
        ForeingKey.ContextForeingKey context = null;
1866
        try {
1867
            FeatureAttributeDescriptor attr = this.getType().getAttributeDescriptor(attrName);
1868
            if (attr == null) {
1869
                return null;
1870
            }
1871
            if (!attr.isForeingKey()) {
1872
                return null;
1873
            }
1874
            ForeingKey fk = attr.getForeingKey();
1875
            if(fk == null){
1876
                return null;
1877
            }
1878
            context = fk.createContext();
1879
            FeatureStore store = this.getStore();
1880
            if(store instanceof SupportTransactions){
1881
                context.setTransaction(((SupportTransactions) store).getTransaction());
1882
            }
1883
            Feature foreignfeat = fk.getFeature(context, this.get(attrName));
1884
            return foreignfeat;
1885
        } catch (Exception ex) {
1886
            return null;
1887
        } finally {
1888
            DisposeUtils.disposeQuietly(context);
1889
        }
1890
    }
1891

    
1892

    
1893
    @Override
1894
    public Expression createFilter() {
1895
        FeatureType ftype = this.getType();
1896
        FeatureAttributeDescriptor[] pk = ftype.getPrimaryKey();
1897
        if( ArrayUtils.isEmpty(pk) ) {
1898
            return null;
1899
        }
1900
        ExpressionBuilder builder = ExpressionUtils.createExpressionBuilder();
1901
        for (FeatureAttributeDescriptor attrdesc : pk) {
1902
            Object value = this.get(attrdesc.getName());
1903
            if( value == null ) {
1904
                builder.and(
1905
                        builder.is_null(builder.column(attrdesc.getName()))
1906
                );
1907
            } else {
1908
                builder.and(
1909
                        builder.eq(
1910
                                builder.column(attrdesc.getName()),
1911
                                builder.constant(value)
1912
                        )
1913
                );
1914
            }
1915
        }
1916
        Expression filter = ExpressionUtils.createExpression(builder.toString());                            
1917
        return filter;
1918
    }
1919
}