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

History | View | Annotate | Download (63.7 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
    @Override
665
    public boolean isBroken() {
666
        return this.data.isBroken();
667
    }
668

    
669
    class UnableToGetReferenceException extends BaseRuntimeException {
670

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

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

    
685
        }
686

    
687
    }
688

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
922
                };
923
            }
924

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1230
        throw new IllegalArgumentException(name);
1231
    }
1232

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

    
1237
            Iterator attributeIteraror;
1238

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

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

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

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

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

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

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

    
1280
            DefaultFeature feature;
1281
            int current = 0;
1282

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1814
    @Override
1815
    public List<String> getKeys() {
1816
        List<String> l = new ArrayList<>();
1817
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1818
            l.add(descriptor.getName());
1819
        }
1820
        return l;
1821
    }
1822

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

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

    
1875

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