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

History | View | Annotate | Download (61.8 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.ExpressionUtils;
46
import org.gvsig.fmap.dal.DALLocator;
47
import org.gvsig.fmap.dal.DataTypes;
48
import org.gvsig.fmap.dal.exception.DataEvaluatorRuntimeException;
49
import org.gvsig.fmap.dal.exception.DataException;
50
import org.gvsig.fmap.dal.feature.DataProfile;
51
import org.gvsig.fmap.dal.feature.EditableFeature;
52
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
53
import org.gvsig.fmap.dal.feature.Feature;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
56
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
57
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
58
import org.gvsig.fmap.dal.feature.FeatureReference;
59
import org.gvsig.fmap.dal.feature.FeatureStore;
60
import org.gvsig.fmap.dal.feature.FeatureType;
61
import org.gvsig.fmap.dal.feature.ForeingKey;
62
import org.gvsig.fmap.dal.feature.exception.IllegalValueException;
63
import org.gvsig.fmap.dal.feature.exception.SetReadOnlyAttributeException;
64
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
65
import org.gvsig.fmap.dal.feature.impl.featurereference.FeatureReferenceFactory;
66
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
67
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
68
import org.gvsig.fmap.geom.Geometry;
69
import org.gvsig.fmap.geom.primitive.Envelope;
70
import org.gvsig.json.Json;
71
import org.gvsig.json.JsonArrayBuilder;
72
import org.gvsig.json.JsonObjectBuilder;
73
import org.gvsig.tools.ToolsLocator;
74
import org.gvsig.tools.dataTypes.Coercion;
75
import org.gvsig.tools.dataTypes.CoercionException;
76
import org.gvsig.tools.dataTypes.DataType;
77
import org.gvsig.tools.dataTypes.DataTypesManager;
78
import org.gvsig.tools.dispose.DisposeUtils;
79
import org.gvsig.tools.dynobject.DynField;
80
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_AGGREGATE;
81
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_COLLABORATION;
82
import static org.gvsig.tools.dynobject.DynField.RELATION_TYPE_COMPOSITION;
83
import org.gvsig.tools.dynobject.DynObject;
84
import org.gvsig.tools.evaluator.Evaluator;
85
import org.gvsig.tools.evaluator.EvaluatorData;
86
import org.gvsig.tools.evaluator.EvaluatorException;
87
import org.gvsig.tools.exception.BaseException;
88
import org.gvsig.tools.exception.BaseRuntimeException;
89
import org.gvsig.tools.lang.Cloneable;
90
import org.gvsig.tools.util.Bitmask;
91
import org.slf4j.Logger;
92
import org.slf4j.LoggerFactory;
93

    
94
@SuppressWarnings("UseSpecificCatch")
95
public class DefaultFeature implements Feature, EvaluatorData, Cloneable {
96

    
97
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultFeature.class);
98

    
99
    private static DataTypesManager dataTypesManager = null;
100
    protected FeatureProvider data;
101
    protected FeatureReference reference;
102
    private WeakReference storeRef;
103

    
104
    private boolean inserted = false;
105
    private Object[] extraValuesData;
106
    private Map<String, Object> extraValues; // not persistent
107

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

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

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

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

    
141
        FeatureType sourceType = sourceFeature.getType();
142

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

    
159
    public void setData(FeatureProvider data) {
160
        this.data = data;
161
        this.extraValuesData = null;
162
        this.reference = null;
163
        this.inserted = true;
164
    }
165

    
166
    public FeatureProvider getData() {
167
        return this.data;
168
    }
169

    
170
    protected DataTypesManager getDataTypesManager() {
171
        if (dataTypesManager == null) {
172
            dataTypesManager = ToolsLocator.getDataTypesManager();
173
        }
174
        return dataTypesManager;
175
    }
176

    
177
    public boolean canSetValue(String name) {
178
        return this.canSetValue(this.getType().getAttributeDescriptor(name), null);
179
    }
180

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

    
198
    protected void set(FeatureAttributeDescriptor attribute, Object value) {
199
        int i = attribute.getIndex();
200

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

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

    
225
        }
226

    
227
        if (attribute.getFeatureAttributeGetter() != null) {
228
            value = attribute.getFeatureAttributeGetter().setter(value);
229
        }
230
        this.setforced(i, attribute, value);
231
    }
232

    
233
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
234

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

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

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

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

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

    
356
    public void clear() {
357
        initializeValues();
358
    }
359

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

    
372
    @Override
373
    public FeatureStore getStore() {
374
        return (FeatureStore) this.storeRef.get();
375
    }
376

    
377
    @Override
378
    public FeatureType getType() {
379
        return this.data.getType();
380
    }
381

    
382
    @Override
383
    public EditableFeature getEditable() {
384
        return new DefaultEditableFeature(this);
385
    }
386

    
387
    @Override
388
    public Feature getCopy() {
389
        return new DefaultFeature(this);
390
    }
391

    
392
    @Override
393
    @SuppressWarnings("CloneDoesntCallSuperClone")
394
    public Object clone() throws CloneNotSupportedException {
395
        return new DefaultFeature(this);
396
    }
397

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
656
    @Override
657
    public void validate(int check) throws DataException {
658
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, check);
659
    }
660

    
661
    class UnableToGetReferenceException extends BaseRuntimeException {
662

    
663
        /**
664
         *
665
         */
666
        private static final long serialVersionUID = 1812805035204824163L;
667

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

    
677
        }
678

    
679
    }
680

    
681
    @Override
682
    public List getSRSs() {
683
        // TODO Auto-generated method stub
684
        return null;
685
    }
686

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

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

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

    
755
    @Override
756
    public List getGeometries() {
757
        // TODO Auto-generated method stub
758
        return null;
759
    }
760

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

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

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

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

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

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

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

    
854
    public boolean has_key(String key) {
855
        Object x = this.getType().get(key);
856
        return x != null;
857
    }
858

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

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

    
875
            @Override
876
            public String next() {
877
                return ((FeatureAttributeDescriptor) it.next()).getName();
878
            }
879

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

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

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

    
904
                    @Override
905
                    public Object getValue() {
906
                        return get(name);
907
                    }
908

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

    
914
                };
915
            }
916

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

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

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

    
997
    @Override
998
    public byte[] getByteArray(String name) {
999
        return (byte[]) this.get(name);
1000
    }
1001

    
1002
    @Override
1003
    public byte[] getByteArray(int index) {
1004
        return (byte[]) this.get(index);
1005
    }
1006

    
1007
    @Override
1008
    public Object[] getArray(String name) {
1009
        return (Object[]) this.get(name);
1010
    }
1011

    
1012
    @Override
1013
    public Object[] getArray(int index) {
1014
        return (Object[]) this.get(index);
1015
    }
1016

    
1017
    @Override
1018
    public boolean getBoolean(String name) {
1019
        Boolean value = ((Boolean) this.get(name, Boolean.class, DataTypes.BOOLEAN));
1020
        if (value == null) {
1021
            return false;
1022
        }
1023
        return value;
1024
    }
1025

    
1026
    @Override
1027
    public boolean getBoolean(int index) {
1028
        Boolean value = ((Boolean) this.get(index, Boolean.class, DataTypes.BOOLEAN));
1029
        if (value == null) {
1030
            return false;
1031
        }
1032
        return value;
1033
    }
1034

    
1035
    @Override
1036
    public byte getByte(String name) {
1037
        Byte value = ((Byte) this.get(name, Byte.class, DataTypes.BYTE));
1038
        if (value == null) {
1039
            return 0;
1040
        }
1041
        return value;
1042
    }
1043

    
1044
    @Override
1045
    public byte getByte(int index) {
1046
        Byte value = ((Byte) this.get(index, Byte.class, DataTypes.BYTE));
1047
        if (value == null) {
1048
            return 0;
1049
        }
1050
        return value;
1051
    }
1052

    
1053
    @Override
1054
    public java.sql.Date getDate(String name) {
1055
        java.sql.Date value = ((java.sql.Date) this.get(name, java.sql.Date.class, DataTypes.DATE));
1056
        return value;
1057
    }
1058

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

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

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

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

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

    
1089
    @Override
1090
    public double getDouble(String name) {
1091
        Double value = ((Double) this.get(name, Double.class, DataTypes.DOUBLE));
1092
        if (value == null) {
1093
            return 0;
1094
        }
1095
        return value;
1096
    }
1097

    
1098
    @Override
1099
    public double getDouble(int index) {
1100

    
1101
        Double value = ((Double) this.get(index, Double.class, DataTypes.DOUBLE));
1102
        if (value == null) {
1103
            return 0;
1104
        }
1105
        return value;
1106
    }
1107

    
1108
    @Override
1109
    public BigDecimal getDecimal(String name) {
1110
        BigDecimal value = ((BigDecimal) this.get(name, BigDecimal.class, DataTypes.DECIMAL));
1111
        return value;
1112
    }
1113

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

    
1120
    @Override
1121
    public Feature getFeature(String name) {
1122
        return this.getFeature(this.data.getType().getIndex(name));
1123
    }
1124

    
1125
    @Override
1126
    public Feature getFeature(int index) {
1127
        return (Feature) this.get(index);
1128
    }
1129

    
1130
    @Override
1131
    public float getFloat(String name) {
1132
        Float value = ((Float) this.get(name, Float.class, DataTypes.FLOAT));
1133
        if (value == null) {
1134
            return 0;
1135
        }
1136
        return value;
1137
    }
1138

    
1139
    @Override
1140
    public float getFloat(int index) {
1141
        Float value = ((Float) this.get(index, Float.class, DataTypes.FLOAT));
1142
        if (value == null) {
1143
            return 0;
1144
        }
1145
        return value;
1146
    }
1147

    
1148
    @Override
1149
    public Geometry getGeometry(String name) {
1150
        return (Geometry) this.get(name, Geometry.class, DataTypes.GEOMETRY);
1151
    }
1152

    
1153
    @Override
1154
    public Geometry getGeometry(int index) {
1155
        return (Geometry) this.get(index, Geometry.class, DataTypes.GEOMETRY);
1156
    }
1157

    
1158
    @Override
1159
    public int getInt(String name) {
1160
        Integer value = ((Integer) this.get(name, Integer.class, DataTypes.INT));
1161
        if (value == null) {
1162
            return 0;
1163
        }
1164
        return value;
1165
    }
1166

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

    
1176
    @Override
1177
    public long getLong(String name) {
1178
        Long value = ((Long) this.get(name, Long.class, DataTypes.LONG));
1179
        if (value == null) {
1180
            return 0;
1181
        }
1182
        return value;
1183
    }
1184

    
1185
    @Override
1186
    public long getLong(int index) {
1187
        Long value = ((Long) this.get(index, Long.class, DataTypes.LONG));
1188
        if (value == null) {
1189
            return 0;
1190
        }
1191
        return value;
1192
    }
1193

    
1194
    @Override
1195
    public String getString(String name) {
1196
        return (String) this.get(name, String.class, DataTypes.STRING);
1197
    }
1198

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

    
1204
    @Override
1205
    public Object getContextValue(String name) {
1206
        name = name.toLowerCase();
1207
        if (name.equals("store")) {
1208
            return this.getStore();
1209
        }
1210

    
1211
        if (name.equals("featuretype")) {
1212
            return this.data.getType();
1213
        }
1214

    
1215
        if (name.equals("feature")) {
1216
            return this;
1217
        }
1218

    
1219
        throw new IllegalArgumentException(name);
1220
    }
1221

    
1222
    @Override
1223
    public Iterator getDataNames() {
1224
        class DataNamesIterator implements Iterator {
1225

    
1226
            Iterator attributeIteraror;
1227

    
1228
            DataNamesIterator(DefaultFeature feature) {
1229
                this.attributeIteraror = feature.getType().iterator();
1230
            }
1231

    
1232
            @Override
1233
            public boolean hasNext() {
1234
                return this.attributeIteraror.hasNext();
1235
            }
1236

    
1237
            @Override
1238
            public Object next() {
1239
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1240
                        .next()).getName();
1241
            }
1242

    
1243
            @Override
1244
            public void remove() {
1245
                throw new UnsupportedOperationException();
1246
            }
1247

    
1248
        }
1249
        return new DataNamesIterator(this);
1250
    }
1251

    
1252
    @Override
1253
    public Object getDataValue(String name) {
1254
        name = name.toLowerCase();
1255
        try {
1256
            return get(name);
1257
        } catch (IllegalArgumentException ex) {
1258
            if ("defaultgeometry".equalsIgnoreCase(name)) {
1259
                return this.getDefaultGeometry();
1260
            }
1261
            throw ex;
1262
        }
1263
    }
1264

    
1265
    @Override
1266
    public Iterator getDataValues() {
1267
        class DataValuesIterator implements Iterator {
1268

    
1269
            DefaultFeature feature;
1270
            int current = 0;
1271

    
1272
            DataValuesIterator(DefaultFeature feature) {
1273
                this.feature = feature;
1274
            }
1275

    
1276
            @Override
1277
            public boolean hasNext() {
1278
                return current < feature.getType().size() - 1;
1279
            }
1280

    
1281
            @Override
1282
            public Object next() {
1283
                return feature.get(current++);
1284
            }
1285

    
1286
            @Override
1287
            public void remove() {
1288
                throw new UnsupportedOperationException();
1289
            }
1290

    
1291
        }
1292
        return new DataValuesIterator(this);
1293
    }
1294

    
1295
    @Override
1296
    public boolean hasContextValue(String name) {
1297
        name = name.toLowerCase();
1298
        if (name.equals("store")) {
1299
            return true;
1300
        }
1301

    
1302
        if (name.equals("featuretype")) {
1303
            return true;
1304
        }
1305

    
1306
        return name.equals("feature");
1307
    }
1308

    
1309
    @Override
1310
    public boolean hasDataValue(String name) {
1311
        return this.hasValue(name);
1312
    }
1313

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

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

    
1366
    /**
1367
     * It is a new feature that has already been inserted into the store but has not yet been saved to disk
1368
     * 
1369
     * @return the inserted
1370
     */
1371
    public boolean isInserted() {
1372
        return inserted;
1373
    }
1374

    
1375
    /**
1376
     * If true, marks the feature as already inserted in the vault but has not yet been saved to disk
1377
     * 
1378
     * @param inserted the inserted to set
1379
     */
1380
    public void setInserted(boolean inserted) {
1381
        this.inserted = inserted;
1382
//        this.data.setNew(!inserted);
1383
    }
1384

    
1385
    @Override
1386
    public EvaluatorData getEvaluatorData() {
1387
        return this;
1388
    }
1389

    
1390
    @Override
1391
    public int size() {
1392
        return this.data.getType().size();
1393
    }
1394

    
1395
    public boolean isEmpty() {
1396
        return false;
1397
    }
1398

    
1399
    public Iterator<String> iterator() {
1400
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1401
        return new Iterator<String>() {
1402
            @Override
1403
            public boolean hasNext() {
1404
                return x.hasNext();
1405
            }
1406

    
1407
            @Override
1408
            public String next() {
1409
                return x.next().getName();
1410
            }
1411
        };
1412
    }
1413

    
1414
    public boolean containsKey(String key) {
1415
        return this.data.getType().get(key) != null;
1416
    }
1417

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

    
1444
    @Override
1445
    public void setExtraValue(String name, Object value) {
1446
        if (this.extraValues == null) {
1447
            this.extraValues = new HashMap<>();
1448
        }
1449
        this.extraValues.put(name, value);
1450
    }
1451

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

    
1490
    @Override
1491
    public Object getExtraValue(String name) {
1492
        Object value = this.data.getExtraValue(name);
1493
        return value;
1494
    }
1495

    
1496
    @Override
1497
    public boolean hasExtraValue(String name) {
1498
        return this.data.hasExtraValue(name);
1499
    }
1500

    
1501
    private boolean hasExtraColumnValue(String name) {
1502
        if (this.extraValues != null) {
1503
            if (this.extraValues.containsKey(name)) {
1504
                return true;
1505
            }
1506
        }
1507
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1508
        int index = columns.getIndexOf(name);
1509
        if (index >= 0) {
1510
            return true;
1511
        }
1512
        return false;
1513
    }
1514

    
1515
    private EditableFeatureAttributeDescriptor getExtraColumn(String name) {
1516
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1517
        return columns.get(name);
1518
    }
1519

    
1520
    @Override
1521
    public boolean hasValue(String name) {
1522
        name = name.toLowerCase();
1523
        return this.data.getType().getIndex(name) >= 0
1524
                || hasExtraValue(name)
1525
                || hasExtraColumnValue(name);
1526
    }
1527

    
1528
    @Override
1529
    public Object getExtraValue(int index) {
1530
        return this.data.getExtraValue(index);
1531
    }
1532

    
1533
    @Override
1534
    public JsonObject toJson() {
1535
        JsonObjectBuilder builder = this.toJsonBuilder();
1536
        return builder.build();
1537
    }
1538
    
1539
    public JsonObject toJson(Map<String, Object> props) {
1540
        JsonObjectBuilder builder = this.toJsonBuilder(props);
1541
        return builder.build();
1542
    }
1543

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

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

    
1803
    @Override
1804
    public List<String> getKeys() {
1805
        List<String> l = new ArrayList<>();
1806
        for (FeatureAttributeDescriptor descriptor : this.getType()) {
1807
            l.add(descriptor.getName());
1808
        }
1809
        return l;
1810
    }
1811

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

    
1827
    @Override
1828
    public String format(int index) {
1829
        Object value = this.get(index);
1830
        FeatureType type = this.data.getType();
1831
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
1832
        return attribute.format(value);
1833
    }
1834
    
1835
    @Override
1836
    public Feature getForeignFeature(String attrName) {
1837
        FeatureAttributeDescriptor attr = this.getType().getAttributeDescriptor(attrName);
1838
        if(attr == null){
1839
            return null;
1840
        }
1841
        if (!attr.isForeingKey()){
1842
            return null;
1843
        }
1844
        ForeingKey fk = attr.getForeingKey();
1845
        Feature foreignfeat = fk.getFeature(null, this.get(attrName));
1846
        return foreignfeat;
1847
    }
1848

    
1849
    
1850
}