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

History | View | Annotate | Download (42.3 KB)

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

    
26
import java.lang.ref.WeakReference;
27
import java.math.BigDecimal;
28
import java.time.LocalDateTime;
29
import java.time.ZoneId;
30
import java.time.format.DateTimeFormatter;
31
import java.util.ArrayList;
32
import java.util.Date;
33
import java.util.HashMap;
34
import java.util.Iterator;
35
import java.util.List;
36
import java.util.Map;
37
import java.util.Objects;
38
import javax.json.Json;
39
import javax.json.JsonObject;
40
import javax.json.JsonObjectBuilder;
41
import org.apache.commons.lang3.ArrayUtils;
42
import org.apache.commons.lang3.StringUtils;
43
import org.cresques.cts.IProjection;
44
import org.gvsig.expressionevaluator.ExpressionUtils;
45
import org.gvsig.fmap.dal.DALLocator;
46
import org.gvsig.fmap.dal.DataTypes;
47
import org.gvsig.fmap.dal.exception.DataEvaluatorRuntimeException;
48
import org.gvsig.fmap.dal.exception.DataException;
49
import org.gvsig.fmap.dal.feature.DataProfile;
50
import org.gvsig.fmap.dal.feature.EditableFeature;
51
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
52
import org.gvsig.fmap.dal.feature.Feature;
53
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
54
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
55
import org.gvsig.fmap.dal.feature.FeatureAttributeGetter;
56
import org.gvsig.fmap.dal.feature.FeatureReference;
57
import org.gvsig.fmap.dal.feature.FeatureStore;
58
import org.gvsig.fmap.dal.feature.FeatureType;
59
import org.gvsig.fmap.dal.feature.exception.IllegalValueException;
60
import org.gvsig.fmap.dal.feature.exception.SetReadOnlyAttributeException;
61
import org.gvsig.fmap.dal.feature.impl.dynobjectutils.DynObjectFeatureFacade;
62
import org.gvsig.fmap.dal.feature.spi.DefaultFeatureProvider;
63
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
64
import org.gvsig.fmap.geom.Geometry;
65
import org.gvsig.fmap.geom.primitive.Envelope;
66
import org.gvsig.tools.ToolsLocator;
67
import org.gvsig.tools.dataTypes.Coercion;
68
import org.gvsig.tools.dataTypes.CoercionException;
69
import org.gvsig.tools.dataTypes.DataTypesManager;
70
import org.gvsig.tools.dynobject.DynObject;
71
import org.gvsig.tools.evaluator.Evaluator;
72
import org.gvsig.tools.evaluator.EvaluatorData;
73
import org.gvsig.tools.evaluator.EvaluatorException;
74
import org.gvsig.tools.exception.BaseException;
75
import org.gvsig.tools.exception.BaseRuntimeException;
76
import org.gvsig.tools.lang.Cloneable;
77
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
78
import org.gvsig.tools.dataTypes.DataType;
79

    
80
@SuppressWarnings("UseSpecificCatch")
81
public class DefaultFeature implements Feature, EvaluatorData, Cloneable {
82

    
83
        private static DataTypesManager dataTypesManager = null;
84
        protected FeatureProvider data;
85
        protected FeatureReference reference;
86
        private WeakReference storeRef;
87

    
88
        private boolean inserted = false;
89
  private Object[] extraValuesData;
90
  private Map<String,Object> extraValues; // not persistent
91

    
92
    /*
93
         * Usar con mucha precaucion o mejor no usar. Lo precisa el
94
         * DefaultFeatureSet en la ordenacion.
95
         */
96
        public DefaultFeature(FeatureStore store) {
97
                this.storeRef = new WeakReference(store);
98
                this.reference = null;
99
        }
100

    
101
        public DefaultFeature(FeatureStore store, FeatureProvider data) {
102
                this.data = data;
103
                this.extraValuesData = null;
104
                this.storeRef = new WeakReference(store);
105
                this.reference = null;
106
                this.inserted = !data.isNew();
107
        }
108

    
109
        DefaultFeature(DefaultFeature feature) {
110
                this.data = feature.data.getCopy();
111
                this.extraValuesData = ArrayUtils.clone(feature.extraValuesData);
112
                this.storeRef = feature.storeRef;
113
                this.reference = feature.reference;
114
                this.inserted = feature.isInserted();
115
        }
116

    
117
    public DefaultFeature(FeatureType targetType, Feature sourceFeature) {
118
        DefaultFeature defaultFeature = (DefaultFeature)sourceFeature;
119
        this.data = new DefaultFeatureProvider(targetType, (DefaultFeatureProvider)defaultFeature.getData());
120
        this.extraValuesData = null;
121
        this.storeRef = defaultFeature.storeRef;
122
        this.reference = defaultFeature.reference;
123
        this.inserted = defaultFeature.isInserted();
124

    
125
        FeatureType sourceType = sourceFeature.getType();
126

    
127
        for (FeatureAttributeDescriptor targetAttrDescriptor : targetType) {
128
            if ( targetAttrDescriptor.isComputed() ) {
129
                 continue;
130
            }
131
            int sourceIndex = sourceType.getIndex(targetAttrDescriptor.getName());
132
            if (sourceIndex<0){
133
                continue;
134
            }
135
            Object value = sourceFeature.get(sourceIndex);
136
            if (value == null && !targetAttrDescriptor.allowNull()) {
137
                continue;
138
            }
139
            this.setforced(targetAttrDescriptor.getIndex(), targetAttrDescriptor,value);
140
        }
141
    }
142

    
143
        public void setData(FeatureProvider data) {
144
                this.data = data;
145
                this.extraValuesData = null;
146
                this.reference = null;
147
                this.inserted = true;
148
        }
149

    
150
        public FeatureProvider getData() {
151
                return this.data;
152
        }
153

    
154
        protected DataTypesManager getDataTypesManager() {
155
                if( dataTypesManager==null ) {
156
                        dataTypesManager = ToolsLocator.getDataTypesManager();
157
                }
158
                return dataTypesManager;
159
        }
160

    
161
    protected void set(FeatureAttributeDescriptor attribute, Object value) {
162
        int i = attribute.getIndex();
163

    
164
        if ( attribute.isReadOnly() ) {
165
            throw new SetReadOnlyAttributeException(attribute.getName(), this.getType());
166
        }
167
        FeatureAttributeEmulator emulator = attribute.getFeatureAttributeEmulator();
168
        if( emulator!= null ) {
169
            emulator.set((EditableFeature) this,value);
170
            return;
171
        }
172

    
173
        if ( value == null ) {
174
            if ( !attribute.allowNull() ) {
175
                if ( !attribute.isAutomatic() ) {
176
                    throw new IllegalValueException(attribute, value);
177
                }
178
            }
179
            this.data.set(i, null);
180
            return;
181

    
182
        }
183

    
184
        if ( attribute.getFeatureAttributeGetter() != null ) {
185
            value = attribute.getFeatureAttributeGetter().setter(value);
186
        }
187
        this.setforced(i, attribute, value);
188
    }
189

    
190
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
191

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

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

    
241
    private Object get(int index,Class theClass, int type) {
242
        Object value = this.get(index);
243
        if( theClass.isInstance(value) ) {
244
            return value;
245
        }
246
        try {
247
            return this.getDataTypesManager().coerce(type, value);
248
        } catch (CoercionException e) {
249

    
250
            if (value == null) {
251
                return null;
252
            }
253
            throw new IllegalArgumentException(
254
                    "Can't convert to "+theClass.getName()+
255
                    " from '"+value.getClass().getName()+
256
                    "' with value '"+value.toString()+"'.");
257
        }
258
    }
259

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

    
285
    public void clear() {
286
        initializeValues();
287
    }
288

    
289
    public void initializeValues(Feature feature) {
290
        FeatureType myType=this.getType();
291
        FeatureType type =feature.getType();
292
        extraValuesData = null;
293
        for (FeatureAttributeDescriptor attribute : type) {
294
            FeatureAttributeDescriptor myAttribute=myType.getAttributeDescriptor(attribute.getName());
295
            if (myAttribute != null) {
296
                this.set(myAttribute, feature.get(attribute.getIndex()));
297
            }
298
        }
299
    }
300

    
301

    
302
    @Override
303
    public FeatureStore getStore() {
304
        return (FeatureStore) this.storeRef.get();
305
    }
306

    
307
    @Override
308
    public FeatureType getType() {
309
        return this.data.getType();
310
    }
311

    
312
    @Override
313
    public EditableFeature getEditable() {
314
        return new DefaultEditableFeature(this);
315
    }
316

    
317
    @Override
318
    public Feature getCopy() {
319
        return new DefaultFeature(this);
320
    }
321

    
322
    @Override
323
    @SuppressWarnings("CloneDoesntCallSuperClone")
324
    public Object clone() throws CloneNotSupportedException {
325
        return new DefaultFeature(this);
326
    }
327

    
328
    @Override
329
    public FeatureReference getReference() {
330
        if (this.reference == null) {
331
            if (!isInserted()) {
332
                return null;
333
            }
334
            reference = new DefaultFeatureReference(this);
335
        }
336
        return this.reference;
337
    }
338

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

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

    
361
    @Override
362
    public int getIntOrDefault(String name, int defaultValue) {
363
        int index = this.data.getType().getIndex(name);
364
        if( index < 0 ) {
365
            return defaultValue;
366
        }
367
        try {
368
            return (int) this.get(index);
369
        } catch(Throwable th) {
370
            return defaultValue;
371
        }
372
    }
373

    
374
    @Override
375
    public long getLongOrDefault(String name, long defaultValue) {
376
        int index = this.data.getType().getIndex(name);
377
        if( index < 0 ) {
378
            return defaultValue;
379
        }
380
        try {
381
            return (long) this.get(index);
382
        } catch(Throwable th) {
383
            return defaultValue;
384
        }
385
    }
386

    
387
    @Override
388
    public float getFloatOrDefault(String name, float defaultValue) {
389
        int index = this.data.getType().getIndex(name);
390
        if( index < 0 ) {
391
            return defaultValue;
392
        }
393
        try {
394
            return (float) this.get(index);
395
        } catch(Throwable th) {
396
            return defaultValue;
397
        }
398
    }
399

    
400
    @Override
401
    public double getDoubleOrDefault(String name, double defaultValue) {
402
        int index = this.data.getType().getIndex(name);
403
        if( index < 0 ) {
404
            return defaultValue;
405
        }
406
        try {
407
            return (double) this.get(index);
408
        } catch(Throwable th) {
409
            return defaultValue;
410
        }
411
    }
412

    
413
    @Override
414
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
415
        int index = this.data.getType().getIndex(name);
416
        if( index < 0 ) {
417
            return defaultValue;
418
        }
419
        try {
420
            return (BigDecimal) this.get(index);
421
        } catch(Throwable th) {
422
            return defaultValue;
423
        }
424
    }
425

    
426
    @Override
427
    public Date getDateOrDefault(String name, Date defaultValue) {
428
        int index = this.data.getType().getIndex(name);
429
        if( index < 0 ) {
430
            return defaultValue;
431
        }
432
        try {
433
            return (Date) this.get(index);
434
        } catch(Throwable th) {
435
            return defaultValue;
436
        }
437
    }
438

    
439
    @Override
440
    public Object getOrDefault(int index, Object defaultValue) {
441
        if( index < 0 || index >= this.data.getType().size() ) {
442
            return defaultValue;
443
        }
444
        try {
445
            return this.get(index);
446
        } catch(Throwable th) {
447
            return defaultValue;
448
        }
449
    }
450

    
451
    @Override
452
    public String getStringOrDefault(int index, String defaultValue) {
453
        if( index < 0 || index >= this.data.getType().size() ) {
454
            return defaultValue;
455
        }
456
        try {
457
            return (String) this.get(index);
458
        } catch(Throwable th) {
459
            return defaultValue;
460
        }
461
    }
462

    
463
    @Override
464
    public int getIntOrDefault(int index, int defaultValue) {
465
        if( index < 0 || index >= this.data.getType().size() ) {
466
            return defaultValue;
467
        }
468
        try {
469
            return (int) this.get(index);
470
        } catch(Throwable th) {
471
            return defaultValue;
472
        }
473
    }
474

    
475
    @Override
476
    public long getLongOrDefault(int index, long defaultValue) {
477
        if( index < 0 || index >= this.data.getType().size() ) {
478
            return defaultValue;
479
        }
480
        try {
481
            return (long) this.get(index);
482
        } catch(Throwable th) {
483
            return defaultValue;
484
        }
485
    }
486

    
487
    @Override
488
    public float getFloatOrDefault(int index, float defaultValue) {
489
        if( index < 0 || index >= this.data.getType().size() ) {
490
            return defaultValue;
491
        }
492
        try {
493
            return (float) this.get(index);
494
        } catch(Throwable th) {
495
            return defaultValue;
496
        }
497
    }
498

    
499
    @Override
500
    public double getDoubleOrDefault(int index, double defaultValue) {
501
        if( index < 0 || index >= this.data.getType().size() ) {
502
            return defaultValue;
503
        }
504
        try {
505
            return (double) this.get(index);
506
        } catch(Throwable th) {
507
            return defaultValue;
508
        }
509
    }
510

    
511
    @Override
512
    public BigDecimal getDecimalOrDefault(int index, BigDecimal defaultValue) {
513
        if( index < 0 || index >= this.data.getType().size() ) {
514
            return defaultValue;
515
        }
516
        try {
517
            return (BigDecimal) this.get(index);
518
        } catch(Throwable th) {
519
            return defaultValue;
520
        }
521
    }
522

    
523
    @Override
524
    public Date getDateOrDefault(int index, Date defaultValue) {
525
        if( index < 0 || index >= this.data.getType().size() ) {
526
            return defaultValue;
527
        }
528
        try {
529
            return (Date) this.get(index);
530
        } catch(Throwable th) {
531
            return defaultValue;
532
        }
533
    }
534

    
535
    class UnableToGetReferenceException extends BaseRuntimeException {
536

    
537
        /**
538
         *
539
         */
540
        private static final long serialVersionUID = 1812805035204824163L;
541

    
542
        /**
543
         * @param exception
544
         */
545
        @SuppressWarnings("OverridableMethodCallInConstructor")
546
        public UnableToGetReferenceException(BaseException exception) {
547
            super("Unable to get reference", "_UnableToGetReferenceException",
548
                serialVersionUID);
549
            this.initCause(exception);
550

    
551
        }
552

    
553
    }
554

    
555
    @Override
556
    public void validate(int mode) throws DataException  {
557
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, mode);
558
    }
559

    
560
    @Override
561
    public List getSRSs() {
562
        // TODO Auto-generated method stub
563
        return null;
564
    }
565

    
566
    @Override
567
    public Envelope getDefaultEnvelope() {
568
        Envelope envelope = this.data.getDefaultEnvelope();
569
        if( envelope == null ) {
570
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
571
            if( i<0 ) {
572
                return null;
573
            }
574
            Geometry geom = this.getDefaultGeometry();
575
            if( geom!=null ) {
576
                envelope = geom.getEnvelope();
577
            }
578
        }
579
        return envelope;
580
    }
581

    
582
    @Override
583
    public Geometry getDefaultGeometry() {
584
            Geometry geom = this.data.getDefaultGeometry();
585
        if( geom == null ) {
586
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
587
            if( i<0 ) {
588
                return null;
589
            }
590
            Object x = this.get(i);
591
            if( x instanceof Geometry ) {
592
                geom = (Geometry) x;
593
            } else {
594
                geom = this.getGeometry(i);
595
            }
596
        }
597
        if( geom != null ) {
598
            if( geom.getProjection()==null ) {
599
                FeatureType type = this.getType();
600
                DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
601
                IProjection proj = attrdesc.getSRS(this.storeRef);
602
                geom.setProjection(proj);
603
            }
604
        }
605
        return geom;
606
    }
607

    
608
//    @Override
609
//    public Time getDefaultTime() {
610
//            Time time = this.data.getDefaultTime();
611
//        if( time == null ) {
612
//            int i = this.data.getType().getDefaultTimeAttributeIndex();
613
//            Object x = this.get(i);
614
//            if( x instanceof Time ) {
615
//                time = (Time) x;
616
//            } else {
617
//                time = this.getTime(i);
618
//            }
619
//        }
620
//        return time;
621
//    }
622
//
623
    @Override
624
    public IProjection getDefaultSRS() {
625
        IProjection srs = this.data.getType().getDefaultSRS();
626
        if( srs == null ) {
627
            FeatureType type = this.getType();
628
            DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
629
            srs = attrdesc.getSRS(this.storeRef);
630
        }
631
        return srs;
632
    }
633

    
634
    @Override
635
    public List getGeometries() {
636
        // TODO Auto-generated method stub
637
        return null;
638
    }
639

    
640
    @Override
641
    public Object getFromProfile(int index) {
642
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
643
        Object value = this.get(index);
644
        String profileName = descriptor.getDataProfileName();
645
        if( StringUtils.isBlank(profileName) ) {
646
            return value;
647
        }
648
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
649
        if( profile==null ) {
650
            return value;
651
        }
652
        return profile.createData(value, descriptor.getTags());
653
    }
654

    
655
    @Override
656
    public Object getFromProfile(String name) {
657
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
658
        return this.getFromProfile(descriptor.getIndex());
659
    }
660

    
661
    @Override
662
    public Object get(String name) {
663
        int index = this.data.getType().getIndex(name);
664
        if( index < 0 ) {
665
            // buscamos en los extra cols
666
            if(hasExtraColumnValue(name)) {
667
                return getExtraColumnValue(name);
668
            }
669
            if (hasExtraValue(name)) {
670
                return getExtraValue(name);
671
            }
672
            // y si esta ahi return
673
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
674
        }
675
        return this.get(index);
676
    }
677
    
678
    @Override
679
    public boolean isNull(int index) {
680
        FeatureType type = this.data.getType();
681
        if( index <0 || index >= type.size() ) {
682
            throw new IllegalArgumentException("Attribute index '"+index+"' out of range (0 to "+this.data.getType().size()+".");
683
        }
684
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
685
        if (!this.data.getType().hasEvaluators()) {
686
            return this.data.get(index)==null;
687
        }
688
        Evaluator eval = attribute.getEvaluator();
689
        if (eval == null) {
690
            return this.data.get(index)==null;
691
        }
692
        Object value = this.data.get(index);
693
        if (value != null) {
694
            return true;
695
        }
696
        try {
697
            value = eval.evaluate(this);
698
        } catch (EvaluatorException e) {
699
            throw new DataEvaluatorRuntimeException(e);
700
        }
701
        this.data.set(index, value);
702
        return value==null;
703
    }
704
    
705
    @Override
706
    public boolean isNull(String name) {
707
        int index = this.data.getType().getIndex(name);
708
        if( index < 0 ) {
709
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
710
        }
711
        return this.isNull(index);
712
    }
713

    
714
    public boolean has_key(String key) {
715
        Object x = this.getType().get(key);
716
        return x != null;
717
    }
718

    
719
    public List<String> keys() {
720
        List<String> ks = new ArrayList<>();
721
        for( FeatureAttributeDescriptor attr : this.getType()) {
722
            ks.add(attr.getName());
723
        }
724
        return ks;
725
    }
726

    
727
    public Iterator<String> iterkeys() {
728
        final Iterator it = this.getType().iterator();
729
        return new Iterator<String>() {
730
            @Override
731
            public boolean hasNext() {
732
                return it.hasNext();
733
            }
734

    
735
            @Override
736
            public String next() {
737
                return ((FeatureAttributeDescriptor)it.next()).getName();
738
            }
739

    
740
            @Override
741
            public void remove() {
742
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
743
            }
744
        };
745
    }
746

    
747
    public Iterator iteritems() {
748
        final Iterator it = this.getType().iterator();
749
        return new Iterator<Map.Entry>() {
750
            @Override
751
            public boolean hasNext() {
752
                return it.hasNext();
753
            }
754

    
755
            @Override
756
            public Map.Entry next() {
757
                final String name = ((FeatureAttributeDescriptor)it.next()).getName();
758
                return new Map.Entry<String, Object>() {
759
                    @Override
760
                    public String getKey() {
761
                        return name;
762
                    }
763

    
764
                    @Override
765
                    public Object getValue() {
766
                        return get(name);
767
                    }
768

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

    
774
                };
775
            }
776

    
777
            @Override
778
            public void remove() {
779
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
780
            }
781
        };
782
    }
783

    
784
    @Override
785
    public Object get(int index) {
786
        FeatureType type = this.data.getType();
787
        if( index <0 || index >= type.size() ) {
788
            throw new IllegalArgumentException("Attribute index '"+index+"' out of range (0 to "+this.data.getType().size()+".");
789
        }
790
        Object value = this.data.get(index);
791
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
792
        if (type.hasEvaluators()) {
793
          Evaluator eval = attribute.getEvaluator();
794
          if (eval != null) {
795
            if (value == null) { // Ya hemos calculado el campo ?
796
              // FIXME: para comprobar si esta calculado usar un array especifico.
797
              try {
798
                  value = eval.evaluate(this);
799
              } catch (EvaluatorException e) {
800
                  throw new DataEvaluatorRuntimeException(e);
801
              }
802
              this.data.set(index, value);
803
            }          
804
          }
805
        }
806
        value = get(attribute, value);
807
        return  value;
808
    }
809

    
810
    private Object get(FeatureAttributeDescriptor featureAttributeDescriptor, Object value){
811
        FeatureAttributeEmulator emulator = featureAttributeDescriptor.getFeatureAttributeEmulator();
812
        if( emulator != null ) {
813
//            int index = featureAttributeDescriptor.getIndex();
814
//            value = this.data.get(index);
815
//            if( value==null ) {
816
                value = emulator.get(this);
817
//                this.data.set(index,value);
818
//            }
819
        } else {
820
            FeatureAttributeGetter getter = featureAttributeDescriptor.getFeatureAttributeGetter();
821
            if( getter != null ) {
822
                value = getter.getter(value);
823
            }
824
        }
825
        DataType dataType = featureAttributeDescriptor.getDataType();
826
        Class<? extends DataType> theClass = dataType.getDefaultClass();
827
        if( theClass!=null && !theClass.isInstance(value) ) {
828
            try {
829
                value = this.getDataTypesManager().coerce(dataType.getType(), value);
830
            } catch (CoercionException e) {
831
                    throw new IllegalArgumentException(
832
                            "Can't convert to "+theClass.getSimpleName()+
833
                            " from '"+value.getClass().getSimpleName()+
834
                            "' with value '"+value.toString()+"'.");
835
            }
836
        }
837
        if( featureAttributeDescriptor.getType()==DataTypes.GEOMETRY ) {
838
            if( value != null ) {
839
                Geometry geom = (Geometry)value;
840
                if( geom.getProjection()==null ) {
841
                    IProjection proj = ((DefaultFeatureAttributeDescriptor)featureAttributeDescriptor).getSRS(this.storeRef);
842
                    geom.setProjection(proj);
843
                }
844
            }
845
        }
846
        return value;
847
    }
848

    
849
    @Override
850
    public byte[] getByteArray(String name) {
851
        return this.getByteArray(this.data.getType().getIndex(name));
852
    }
853

    
854
    @Override
855
    public byte[] getByteArray(int index) {
856
        return (byte[]) this.get(index);
857
    }
858

    
859
    @Override
860
    public Object[] getArray(String name) {
861
        return this.getArray(this.data.getType().getIndex(name));
862
    }
863

    
864
    @Override
865
    public Object[] getArray(int index) {
866
        return (Object[]) this.get(index);
867
    }
868

    
869
    @Override
870
    public boolean getBoolean(String name) {
871
        return this.getBoolean(this.data.getType().getIndex(name));
872
    }
873

    
874
    @Override
875
    public boolean getBoolean(int index) {
876
        Boolean value = ((Boolean) this.get(index,Boolean.class,DataTypes.BOOLEAN));
877
        if (value == null) {
878
            return false;
879
        }
880
        return value;
881
    }
882

    
883
    @Override
884
    public byte getByte(String name) {
885
        return this.getByte(this.data.getType().getIndex(name));
886
    }
887

    
888
    @Override
889
    public byte getByte(int index) {
890
        Byte value = ((Byte) this.get(index,Byte.class,DataTypes.BYTE));
891
        if (value == null) {
892
            return 0;
893
        }
894
        return value;
895
    }
896

    
897
    @Override
898
    public Date getDate(String name) {
899
        return this.getDate(this.data.getType().getIndex(name));
900
    }
901

    
902
    @Override
903
    public Date getDate(int index) {
904
        Date value = ((Date) this.get(index,java.sql.Date.class,DataTypes.DATE));
905
        return value;
906
    }
907

    
908
    @Override
909
    public Date getTime(String name) {
910
        return this.getTime(this.data.getType().getIndex(name));
911
    }
912

    
913
    @Override
914
    public Date getTime(int index) {
915
        Date value = ((Date) this.get(index,java.sql.Time.class,DataTypes.TIME));
916
        return value;
917
    }
918

    
919
    @Override
920
    public Date getTimestamp(String name) {
921
        return this.getTimestamp(this.data.getType().getIndex(name));
922
    }
923

    
924
    @Override
925
    public Date getTimestamp(int index) {
926
        Date value = ((Date) this.get(index,java.sql.Timestamp.class,DataTypes.TIMESTAMP));
927
        return value;
928
    }
929

    
930
    @Override
931
    public double getDouble(String name) {
932
        return this.getDouble(this.data.getType().getIndex(name));
933
    }
934

    
935
    @Override
936
    public double getDouble(int index) {
937

    
938
        Double value = ((Double) this.get(index,Double.class,DataTypes.DOUBLE));
939
        if (value == null) {
940
            return 0;
941
        }
942
        return value;
943
    }
944

    
945
    @Override
946
    public BigDecimal getDecimal(String name) {
947
        return this.getDecimal(this.data.getType().getIndex(name));
948
    }
949

    
950
    @Override
951
    public BigDecimal getDecimal(int index) {
952
        BigDecimal value = ((BigDecimal) this.get(index,BigDecimal.class,DataTypes.DECIMAL));
953
        return value;
954
    }
955

    
956
    @Override
957
    public Feature getFeature(String name) {
958
        return this.getFeature(this.data.getType().getIndex(name));
959
    }
960

    
961
    @Override
962
    public Feature getFeature(int index) {
963
        return (Feature) this.get(index);
964
    }
965

    
966
    @Override
967
    public float getFloat(String name) {
968
        return this.getFloat(this.data.getType().getIndex(name));
969
    }
970

    
971
    @Override
972
    public float getFloat(int index) {
973
        Float value = ((Float) this.get(index,Float.class,DataTypes.FLOAT));
974
        if (value == null) {
975
            return 0;
976
        }
977
        return value;
978
    }
979

    
980
    @Override
981
    public Geometry getGeometry(String name) {
982
        return this.getGeometry(this.data.getType().getIndex(name));
983
    }
984

    
985
    @Override
986
    public Geometry getGeometry(int index) {
987
        return (Geometry) this.get(index,Geometry.class,DataTypes.GEOMETRY);
988
    }
989

    
990
    @Override
991
    public int getInt(String name) {
992
        return this.getInt(this.data.getType().getIndex(name));
993
    }
994

    
995
    @Override
996
    public int getInt(int index) {
997
        Integer value = ((Integer) this.get(index,Integer.class,DataTypes.INT));
998
        if (value == null) {
999
            return 0;
1000
        }
1001
        return value;
1002
    }
1003

    
1004
    @Override
1005
    public long getLong(String name) {
1006
        return this.getLong(this.data.getType().getIndex(name));
1007
    }
1008

    
1009
    @Override
1010
    public long getLong(int index) {
1011
        Long value = ((Long) this.get(index,Long.class,DataTypes.LONG));
1012
        if (value == null) {
1013
            return 0;
1014
        }
1015
        return value;
1016
    }
1017

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

    
1023
    @Override
1024
    public String getString(int index) {
1025
        return (String) this.get(index,String.class,DataTypes.STRING);
1026
    }
1027

    
1028
    @Override
1029
    public Object getContextValue(String name) {
1030
        name = name.toLowerCase();
1031
        if (name.equals("store")) {
1032
            return this.getStore();
1033
        }
1034

    
1035
        if (name.equals("featuretype")) {
1036
            return this.data.getType();
1037
        }
1038

    
1039
        if (name.equals("feature")) {
1040
            return this;
1041
        }
1042

    
1043
        throw new IllegalArgumentException(name);
1044
    }
1045

    
1046
    @Override
1047
    public Iterator getDataNames() {
1048
        class DataNamesIterator implements Iterator {
1049
            Iterator attributeIteraror;
1050

    
1051
            DataNamesIterator(DefaultFeature feature) {
1052
                this.attributeIteraror = feature.getType().iterator();
1053
            }
1054

    
1055
            @Override
1056
            public boolean hasNext() {
1057
                return this.attributeIteraror.hasNext();
1058
            }
1059

    
1060
            @Override
1061
            public Object next() {
1062
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1063
                        .next()).getName();
1064
            }
1065

    
1066
            @Override
1067
            public void remove() {
1068
                throw new UnsupportedOperationException();
1069
            }
1070

    
1071
        }
1072
        return new DataNamesIterator(this);
1073
    }
1074

    
1075
    @Override
1076
    public Object getDataValue(String name) {
1077
        name = name.toLowerCase();
1078
        try {
1079
            return get(name);
1080
        } catch (IllegalArgumentException ex) {
1081
            if( "defaultgeometry".equalsIgnoreCase(name )) {
1082
                return this.getDefaultGeometry();
1083
            }
1084
            throw ex;
1085
        }
1086
    }
1087

    
1088
    @Override
1089
    public Iterator getDataValues() {
1090
        class DataValuesIterator implements Iterator {
1091
            DefaultFeature feature;
1092
            int current = 0;
1093

    
1094
            DataValuesIterator(DefaultFeature feature) {
1095
                this.feature = feature;
1096
            }
1097

    
1098
            @Override
1099
            public boolean hasNext() {
1100
                return current < feature.getType().size() - 1;
1101
            }
1102

    
1103
            @Override
1104
            public Object next() {
1105
                return feature.get(current++);
1106
            }
1107

    
1108
            @Override
1109
            public void remove() {
1110
                throw new UnsupportedOperationException();
1111
            }
1112

    
1113
        }
1114
        return new DataValuesIterator(this);
1115
    }
1116

    
1117
    @Override
1118
    public boolean hasContextValue(String name) {
1119
        name = name.toLowerCase();
1120
        if (name.equals("store")) {
1121
            return true;
1122
        }
1123

    
1124
        if (name.equals("featuretype")) {
1125
            return true;
1126
        }
1127

    
1128
        return name.equals("feature");
1129
    }
1130

    
1131
    @Override
1132
    public boolean hasDataValue(String name) {
1133
        name = name.toLowerCase();
1134
        return this.data.getType().getIndex(name) >= 0;
1135
    }
1136

    
1137
//    @Override
1138
//    public Time getTime(int index) {
1139
//        return ((Time) this.get(index,Time.class,DataTypes.INSTANT));
1140
//    }
1141
//
1142
//    @Override
1143
//    public Time getTime(String name) {
1144
//        return this.getInstant(this.data.getType().getIndex(name));
1145
//    }
1146
//
1147
//    @Override
1148
//    public Instant getInstant(int index) {
1149
//        return ((Instant) this.get(index,Instant.class,DataTypes.INSTANT));
1150
//    }
1151
//
1152
//    @Override
1153
//    public Instant getInstant(String name) {
1154
//        return this.getInstant(this.data.getType().getIndex(name));
1155
//    }
1156
//
1157
//    @Override
1158
//    public Interval getInterval(int index) {
1159
//        return ((Interval) this.get(index,Interval.class,DataTypes.INTERVAL));
1160
//    }
1161
//
1162
//    @Override
1163
//    public Interval getInterval(String name) {
1164
//        return this.getInterval(this.data.getType().getIndex(name));
1165
//    }
1166
//
1167
    @Override
1168
    public DynObject getAsDynObject() {
1169
        DynObjectFeatureFacade facade = new DynObjectFeatureFacade(this);
1170
        return facade;
1171
    }
1172

    
1173
    @Override
1174
    public String toString() {
1175
            StringBuilder builder = new StringBuilder();
1176
        FeatureAttributeDescriptor[] attributeDescriptors =
1177
            getType().getAttributeDescriptors();
1178
        for (int i = 0; i < attributeDescriptors.length; i++) {
1179
            String name = attributeDescriptors[i].getName();
1180
            Object value = get(name);
1181
            builder.append(value);
1182
            if (i < attributeDescriptors.length - 1) {
1183
                builder.append(", ");
1184
            }
1185
        }
1186
        return builder.toString();
1187
    }
1188

    
1189

    
1190

    
1191

    
1192
        /**
1193
     * @return the inserted
1194
     */
1195
    public boolean isInserted() {
1196
        return inserted;
1197
    }
1198

    
1199

    
1200
    /**
1201
     * @param inserted the inserted to set
1202
     */
1203
    public void setInserted(boolean inserted) {
1204
        this.inserted = inserted;
1205
    }
1206

    
1207
        @Override
1208
    public EvaluatorData getEvaluatorData() {
1209
        return this;
1210
    }
1211

    
1212
    @Override
1213
    public int size() {
1214
        return this.data.getType().size();
1215
    }
1216
    
1217
    public boolean isEmpty() {
1218
        return false;
1219
    }
1220

    
1221
    public Iterator<String> iterator() {
1222
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1223
        return new Iterator<String>() {
1224
            @Override
1225
            public boolean hasNext() {
1226
                return x.hasNext();
1227
            }
1228

    
1229
            @Override
1230
            public String next() {
1231
                return x.next().getName();
1232
            }
1233
        };
1234
    }
1235
    
1236
    public boolean containsKey(String key) {
1237
        return this.data.getType().get(key)!=null;
1238
    }
1239

    
1240
    @Override
1241
    public String getLabelOfValue(String name) {
1242
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1243
        if( attrdesc==null ) {
1244
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
1245
        }
1246
        Object value = this.get(attrdesc.getIndex());
1247
        String label = attrdesc.getLabelOfValue(value);
1248
        return label;
1249
    }
1250
   
1251
    @Override
1252
    public void setExtraValue(String name, Object value) {
1253
      if( this.extraValues==null ) {
1254
        this.extraValues = new HashMap<>();
1255
      }
1256
      this.extraValues.put(name, value);
1257
    }
1258
    
1259
    public Object getExtraColumnValue(String name) {
1260
        Object value;
1261
        if( this.extraValues!=null ) {
1262
          if( this.extraValues.containsKey(name) ) {
1263
            return this.extraValues.get(name);
1264
          }
1265
        }
1266
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1267
        int index = columns.getIndexOf(name);
1268
        if( index >= 0 ) {
1269
          if( extraValuesData==null ) {
1270
            extraValuesData = new Object[columns.size()];
1271
            EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1272
            value = attrdesc.getFeatureAttributeEmulator().get(this);
1273
            extraValuesData[index] = value;
1274
          } else {
1275
            value = extraValuesData[index];
1276
            if( value == null ) {
1277
              EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1278
              value = attrdesc.getFeatureAttributeEmulator().get(this);
1279
              extraValuesData[index] = value;
1280
            }
1281
          }
1282
          return value;
1283
        }
1284
        throw new RuntimeException("Not extra column value found");
1285
    }
1286

    
1287
    @Override
1288
    public Object getExtraValue(String name) {
1289
        Object value = this.data.getExtraValue(name);
1290
        return value;
1291
    }
1292

    
1293
    @Override
1294
    public boolean hasExtraValue(String name) {
1295
        return this.data.hasExtraValue(name);
1296
    }
1297
    
1298

    
1299
    private boolean hasExtraColumnValue(String name) {
1300
        if( this.extraValues!=null ) {
1301
          if( this.extraValues.containsKey(name) ) {
1302
            return true;
1303
          }
1304
        }
1305
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1306
        int index = columns.getIndexOf(name);
1307
        if( index >= 0 ) {
1308
          return true;
1309
        }
1310
        return false;
1311
    }
1312
    
1313
    @Override
1314
    public Object getExtraValue(int index) {
1315
        return this.data.getExtraValue(index);
1316
    }
1317

    
1318
    public JsonObject toJSON() {
1319
        JsonObjectBuilder builder = Json.createObjectBuilder();
1320
        
1321
        FeatureType ft = this.getType();
1322
        for (FeatureAttributeDescriptor desc : ft) {
1323
            if (desc.isComputed()) {
1324
                continue;
1325
            }
1326
            switch(desc.getType()) {
1327
                case DataTypes.GEOMETRY:
1328
                    {
1329
                        try {
1330
                            builder.add(desc.getName(), this.getGeometry(desc.getIndex()).convertToWKT());
1331
                        } catch (Exception ex) {
1332
                            throw new RuntimeException("Can't convert geometry to WKT.", ex);
1333
                        }
1334
                    }
1335
                    break;
1336
                case DataTypes.BOOLEAN:
1337
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1338
                    break;
1339
                case DataTypes.BYTE:
1340
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1341
                    break;
1342
                case DataTypes.INT:
1343
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1344
                    break;
1345
                case DataTypes.LONG:
1346
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1347
                    break;
1348
                case DataTypes.DOUBLE:
1349
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1350
                    break;
1351
                case DataTypes.FLOAT:
1352
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1353
                    break;
1354
                case DataTypes.DATE:
1355
                    // Format date as ISO 8601
1356
                    Date date = this.getDate(desc.getIndex());
1357
                    if( date==null ) {
1358
                        builder.addNull(desc.getName());
1359
                    } else {
1360
                        LocalDateTime localDateTime = LocalDateTime.ofInstant(new Date(date.getTime()).toInstant(), ZoneId.systemDefault());
1361
                        String value = DateTimeFormatter.ISO_DATE_TIME.format(localDateTime);
1362
                        builder.add(desc.getName(), value);
1363
                    }
1364
                    break;
1365
                default:
1366
                    builder.add(desc.getName(), Objects.toString(this.get(desc.getIndex()),""));
1367
            }
1368
        }        
1369
        return builder.build();
1370
    }
1371

    
1372
    @Override
1373
    public List<String> getKeys() {
1374
      List<String> l = new ArrayList<>();
1375
      for (FeatureAttributeDescriptor descriptor : this.getType()) {
1376
        l.add(descriptor.getName());
1377
      }
1378
      return l;
1379
    }
1380

    
1381
}