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

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

    
77
@SuppressWarnings("UseSpecificCatch")
78
public class DefaultFeature implements Feature, EvaluatorData, Cloneable {
79

    
80
        private static DataTypesManager dataTypesManager = null;
81
        protected FeatureProvider data;
82
        protected FeatureReference reference;
83
        private WeakReference storeRef;
84

    
85
        private boolean inserted = false;
86
  private Object[] extraValuesData;
87
  private Map<String,Object> extraValues; // not persistent
88

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

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

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

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

    
122
        FeatureType sourceType = sourceFeature.getType();
123

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

    
140
        public void setData(FeatureProvider data) {
141
                this.data = data;
142
                this.extraValuesData = null;
143
                this.reference = null;
144
                this.inserted = true;
145
        }
146

    
147
        public FeatureProvider getData() {
148
                return this.data;
149
        }
150

    
151
        protected DataTypesManager getDataTypesManager() {
152
                if( dataTypesManager==null ) {
153
                        dataTypesManager = ToolsLocator.getDataTypesManager();
154
                }
155
                return dataTypesManager;
156
        }
157

    
158
    protected void set(FeatureAttributeDescriptor attribute, Object value) {
159
        int i = attribute.getIndex();
160

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

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

    
179
        }
180

    
181
        if ( attribute.getFeatureAttributeGetter() != null ) {
182
            value = attribute.getFeatureAttributeGetter().setter(value);
183
        }
184
        this.setforced(i, attribute, value);
185
    }
186

    
187
    private void setforced(int i, FeatureAttributeDescriptor attribute, Object value) {
188

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

    
213
                }
214
            } 
215
            try {
216
                Coercion coercer = attribute.getDataType().getCoercion();
217
                value= coercer.coerce(value, attribute.getCoercionContext());
218
            } catch (CoercionException e) {
219
                throw new IllegalArgumentException("Can't convert to "
220
                        + attribute.getDataType().getName()
221
                        + " from '"
222
                        + value.getClass().getName() 
223
                        + "' with value '"
224
                        + value.toString() 
225
                        + "' and context '"
226
                        + attribute.getCoercionContext()
227
                        + "'.");
228
            }
229
        }
230
        this.data.set(i, value);
231
    }
232

    
233
    private Object get(int index,Class theClass, int type) {
234
        Object value = this.get(index);
235
        if( theClass.isInstance(value) ) {
236
            return value;
237
        }
238
        try {
239
            return this.getDataTypesManager().coerce(type, value);
240
        } catch (CoercionException e) {
241

    
242
            if (value == null) {
243
                return null;
244
            }
245
            throw new IllegalArgumentException(
246
                    "Can't convert to "+theClass.getName()+
247
                    " from '"+value.getClass().getName()+
248
                    "' with value '"+value.toString()+"'.");
249
        }
250
    }
251

    
252
    public void initializeValues() {
253
        FeatureType type = this.getType();
254
        for (FeatureAttributeDescriptor attribute : type) {
255
            if (attribute.isAutomatic() || attribute.isReadOnly()
256
                    || attribute.isComputed() ) {
257
                continue;
258
            }
259
            if (attribute.getDefaultValue() == null && !attribute.allowNull()) {
260
                continue;
261
            }
262
            Object value =  attribute.getDefaultValue();
263
            if( value instanceof CharSequence ) {
264
              String s = ((CharSequence)value).toString();
265
              if( ExpressionUtils.isDynamicText(s) ) {
266
                try {
267
                  value = ExpressionUtils.evaluateDynamicText(s);
268
                } catch(Throwable th) {
269
                  value = null;
270
                }
271
              }
272
            }
273
            this.set(attribute, value);
274
        }
275
    }
276

    
277
    public void clear() {
278
        initializeValues();
279
    }
280

    
281
    public void initializeValues(Feature feature) {
282
        FeatureType myType=this.getType();
283
        FeatureType type =feature.getType();
284
        extraValuesData = null;
285
        for (FeatureAttributeDescriptor attribute : type) {
286
            FeatureAttributeDescriptor myAttribute=myType.getAttributeDescriptor(attribute.getName());
287
            if (myAttribute != null) {
288
                this.set(myAttribute, feature.get(attribute.getIndex()));
289
            }
290
        }
291
    }
292

    
293

    
294
    @Override
295
    public FeatureStore getStore() {
296
        return (FeatureStore) this.storeRef.get();
297
    }
298

    
299
    @Override
300
    public FeatureType getType() {
301
        return this.data.getType();
302
    }
303

    
304
    @Override
305
    public EditableFeature getEditable() {
306
        return new DefaultEditableFeature(this);
307
    }
308

    
309
    @Override
310
    public Feature getCopy() {
311
        return new DefaultFeature(this);
312
    }
313

    
314
    @Override
315
    @SuppressWarnings("CloneDoesntCallSuperClone")
316
    public Object clone() throws CloneNotSupportedException {
317
        return new DefaultFeature(this);
318
    }
319

    
320
    @Override
321
    public FeatureReference getReference() {
322
        if (this.reference == null) {
323
            if (!isInserted()) {
324
                return null;
325
            }
326
            reference = new DefaultFeatureReference(this);
327
        }
328
        return this.reference;
329
    }
330

    
331
    @Override
332
    public Object getOrDefault(String name, Object defaultValue) {
333
        int index = this.data.getType().getIndex(name);
334
        if( index < 0 ) {
335
            return defaultValue;
336
        }
337
        return this.get(index);
338
    }
339

    
340
    @Override
341
    public String getStringOrDefault(String name, String defaultValue) {
342
        int index = this.data.getType().getIndex(name);
343
        if( index < 0 ) {
344
            return defaultValue;
345
        }
346
        try {
347
            return (String) this.get(index);
348
        } catch(Throwable th) {
349
            return defaultValue;
350
        }
351
    }
352

    
353
    @Override
354
    public int getIntOrDefault(String name, int defaultValue) {
355
        int index = this.data.getType().getIndex(name);
356
        if( index < 0 ) {
357
            return defaultValue;
358
        }
359
        try {
360
            return (int) this.get(index);
361
        } catch(Throwable th) {
362
            return defaultValue;
363
        }
364
    }
365

    
366
    @Override
367
    public long getLongOrDefault(String name, long defaultValue) {
368
        int index = this.data.getType().getIndex(name);
369
        if( index < 0 ) {
370
            return defaultValue;
371
        }
372
        try {
373
            return (long) this.get(index);
374
        } catch(Throwable th) {
375
            return defaultValue;
376
        }
377
    }
378

    
379
    @Override
380
    public float getFloatOrDefault(String name, float defaultValue) {
381
        int index = this.data.getType().getIndex(name);
382
        if( index < 0 ) {
383
            return defaultValue;
384
        }
385
        try {
386
            return (float) this.get(index);
387
        } catch(Throwable th) {
388
            return defaultValue;
389
        }
390
    }
391

    
392
    @Override
393
    public double getDoubleOrDefault(String name, double defaultValue) {
394
        int index = this.data.getType().getIndex(name);
395
        if( index < 0 ) {
396
            return defaultValue;
397
        }
398
        try {
399
            return (double) this.get(index);
400
        } catch(Throwable th) {
401
            return defaultValue;
402
        }
403
    }
404

    
405
    @Override
406
    public BigDecimal getDecimalOrDefault(String name, BigDecimal defaultValue) {
407
        int index = this.data.getType().getIndex(name);
408
        if( index < 0 ) {
409
            return defaultValue;
410
        }
411
        try {
412
            return (BigDecimal) this.get(index);
413
        } catch(Throwable th) {
414
            return defaultValue;
415
        }
416
    }
417

    
418
    @Override
419
    public Date getDateOrDefault(String name, Date defaultValue) {
420
        int index = this.data.getType().getIndex(name);
421
        if( index < 0 ) {
422
            return defaultValue;
423
        }
424
        try {
425
            return (Date) this.get(index);
426
        } catch(Throwable th) {
427
            return defaultValue;
428
        }
429
    }
430

    
431
    @Override
432
    public Object getOrDefault(int index, Object defaultValue) {
433
        if( index < 0 || index >= this.data.getType().size() ) {
434
            return defaultValue;
435
        }
436
        try {
437
            return this.get(index);
438
        } catch(Throwable th) {
439
            return defaultValue;
440
        }
441
    }
442

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

    
455
    @Override
456
    public int getIntOrDefault(int index, int defaultValue) {
457
        if( index < 0 || index >= this.data.getType().size() ) {
458
            return defaultValue;
459
        }
460
        try {
461
            return (int) this.get(index);
462
        } catch(Throwable th) {
463
            return defaultValue;
464
        }
465
    }
466

    
467
    @Override
468
    public long getLongOrDefault(int index, long defaultValue) {
469
        if( index < 0 || index >= this.data.getType().size() ) {
470
            return defaultValue;
471
        }
472
        try {
473
            return (long) this.get(index);
474
        } catch(Throwable th) {
475
            return defaultValue;
476
        }
477
    }
478

    
479
    @Override
480
    public float getFloatOrDefault(int index, float defaultValue) {
481
        if( index < 0 || index >= this.data.getType().size() ) {
482
            return defaultValue;
483
        }
484
        try {
485
            return (float) this.get(index);
486
        } catch(Throwable th) {
487
            return defaultValue;
488
        }
489
    }
490

    
491
    @Override
492
    public double getDoubleOrDefault(int index, double defaultValue) {
493
        if( index < 0 || index >= this.data.getType().size() ) {
494
            return defaultValue;
495
        }
496
        try {
497
            return (double) this.get(index);
498
        } catch(Throwable th) {
499
            return defaultValue;
500
        }
501
    }
502

    
503
    @Override
504
    public BigDecimal getDecimalOrDefault(int index, BigDecimal defaultValue) {
505
        if( index < 0 || index >= this.data.getType().size() ) {
506
            return defaultValue;
507
        }
508
        try {
509
            return (BigDecimal) this.get(index);
510
        } catch(Throwable th) {
511
            return defaultValue;
512
        }
513
    }
514

    
515
    @Override
516
    public Date getDateOrDefault(int index, Date defaultValue) {
517
        if( index < 0 || index >= this.data.getType().size() ) {
518
            return defaultValue;
519
        }
520
        try {
521
            return (Date) this.get(index);
522
        } catch(Throwable th) {
523
            return defaultValue;
524
        }
525
    }
526

    
527
    class UnableToGetReferenceException extends BaseRuntimeException {
528

    
529
        /**
530
         *
531
         */
532
        private static final long serialVersionUID = 1812805035204824163L;
533

    
534
        /**
535
         * @param exception
536
         */
537
        @SuppressWarnings("OverridableMethodCallInConstructor")
538
        public UnableToGetReferenceException(BaseException exception) {
539
            super("Unable to get reference", "_UnableToGetReferenceException",
540
                serialVersionUID);
541
            this.initCause(exception);
542

    
543
        }
544

    
545
    }
546

    
547
    @Override
548
    public void validate(int mode) throws DataException  {
549
        ((DefaultFeatureType) this.data.getType()).validateFeature(this, mode);
550
    }
551

    
552
    @Override
553
    public List getSRSs() {
554
        // TODO Auto-generated method stub
555
        return null;
556
    }
557

    
558
    @Override
559
    public Envelope getDefaultEnvelope() {
560
        Envelope envelope = this.data.getDefaultEnvelope();
561
        if( envelope == null ) {
562
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
563
            if( i<0 ) {
564
                return null;
565
            }
566
            Geometry geom = this.getDefaultGeometry();
567
            if( geom!=null ) {
568
                envelope = geom.getEnvelope();
569
            }
570
        }
571
        return envelope;
572
    }
573

    
574
    @Override
575
    public Geometry getDefaultGeometry() {
576
            Geometry geom = this.data.getDefaultGeometry();
577
        if( geom == null ) {
578
            int i = this.data.getType().getDefaultGeometryAttributeIndex();
579
            if( i<0 ) {
580
                return null;
581
            }
582
            Object x = this.get(i);
583
            if( x instanceof Geometry ) {
584
                geom = (Geometry) x;
585
            } else {
586
                geom = this.getGeometry(i);
587
            }
588
        }
589
        if( geom != null ) {
590
            if( geom.getProjection()==null ) {
591
                FeatureType type = this.getType();
592
                DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
593
                IProjection proj = attrdesc.getSRS(this.storeRef);
594
                geom.setProjection(proj);
595
            }
596
        }
597
        return geom;
598
    }
599

    
600
//    @Override
601
//    public Time getDefaultTime() {
602
//            Time time = this.data.getDefaultTime();
603
//        if( time == null ) {
604
//            int i = this.data.getType().getDefaultTimeAttributeIndex();
605
//            Object x = this.get(i);
606
//            if( x instanceof Time ) {
607
//                time = (Time) x;
608
//            } else {
609
//                time = this.getTime(i);
610
//            }
611
//        }
612
//        return time;
613
//    }
614
//
615
    @Override
616
    public IProjection getDefaultSRS() {
617
        IProjection srs = this.data.getType().getDefaultSRS();
618
        if( srs == null ) {
619
            FeatureType type = this.getType();
620
            DefaultFeatureAttributeDescriptor attrdesc = (DefaultFeatureAttributeDescriptor) type.get(type.getDefaultGeometryAttributeIndex());
621
            srs = attrdesc.getSRS(this.storeRef);
622
        }
623
        return srs;
624
    }
625

    
626
    @Override
627
    public List getGeometries() {
628
        // TODO Auto-generated method stub
629
        return null;
630
    }
631

    
632
    @Override
633
    public Object getFromProfile(int index) {
634
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(index);
635
        Object value = this.get(index);
636
        String profileName = descriptor.getDataProfileName();
637
        if( StringUtils.isBlank(profileName) ) {
638
            return value;
639
        }
640
        DataProfile profile = DALLocator.getDataManager().getDataProfile(profileName);
641
        if( profile==null ) {
642
            return value;
643
        }
644
        return profile.createData(value, descriptor.getTags());
645
    }
646

    
647
    @Override
648
    public Object getFromProfile(String name) {
649
        FeatureAttributeDescriptor descriptor = this.data.getType().getAttributeDescriptor(name);
650
        return this.getFromProfile(descriptor.getIndex());
651
    }
652

    
653
    @Override
654
    public Object get(String name) {
655
        int index = this.data.getType().getIndex(name);
656
        if( index < 0 ) {
657
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
658
        }
659
        return this.get(index);
660
    }
661
    
662
    @Override
663
    public boolean isNull(int index) {
664
        FeatureType type = this.data.getType();
665
        if( index <0 || index >= type.size() ) {
666
            throw new IllegalArgumentException("Attribute index '"+index+"' out of range (0 to "+this.data.getType().size()+".");
667
        }
668
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
669
        if (!this.data.getType().hasEvaluators()) {
670
            return this.data.get(index)==null;
671
        }
672
        Evaluator eval = attribute.getEvaluator();
673
        if (eval == null) {
674
            return this.data.get(index)==null;
675
        }
676
        Object value = this.data.get(index);
677
        if (value != null) {
678
            return true;
679
        }
680
        try {
681
            value = eval.evaluate(this);
682
        } catch (EvaluatorException e) {
683
            throw new DataEvaluatorRuntimeException(e);
684
        }
685
        this.data.set(index, value);
686
        return value==null;
687
    }
688
    
689
    @Override
690
    public boolean isNull(String name) {
691
        int index = this.data.getType().getIndex(name);
692
        if( index < 0 ) {
693
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
694
        }
695
        return this.isNull(index);
696
    }
697

    
698
    public boolean has_key(String key) {
699
        Object x = this.getType().get(key);
700
        return x != null;
701
    }
702

    
703
    public List<String> keys() {
704
        List<String> ks = new ArrayList<>();
705
        for( FeatureAttributeDescriptor attr : this.getType()) {
706
            ks.add(attr.getName());
707
        }
708
        return ks;
709
    }
710

    
711
    public Iterator<String> iterkeys() {
712
        final Iterator it = this.getType().iterator();
713
        return new Iterator<String>() {
714
            @Override
715
            public boolean hasNext() {
716
                return it.hasNext();
717
            }
718

    
719
            @Override
720
            public String next() {
721
                return ((FeatureAttributeDescriptor)it.next()).getName();
722
            }
723

    
724
            @Override
725
            public void remove() {
726
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
727
            }
728
        };
729
    }
730

    
731
    public Iterator iteritems() {
732
        final Iterator it = this.getType().iterator();
733
        return new Iterator<Map.Entry>() {
734
            @Override
735
            public boolean hasNext() {
736
                return it.hasNext();
737
            }
738

    
739
            @Override
740
            public Map.Entry next() {
741
                final String name = ((FeatureAttributeDescriptor)it.next()).getName();
742
                return new Map.Entry<String, Object>() {
743
                    @Override
744
                    public String getKey() {
745
                        return name;
746
                    }
747

    
748
                    @Override
749
                    public Object getValue() {
750
                        return get(name);
751
                    }
752

    
753
                    @Override
754
                    public Object setValue(Object value) {
755
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
756
                    }
757

    
758
                };
759
            }
760

    
761
            @Override
762
            public void remove() {
763
                throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
764
            }
765
        };
766
    }
767

    
768
    @Override
769
    public Object get(int index) {
770
        FeatureType type = this.data.getType();
771
        if( index <0 || index >= type.size() ) {
772
            throw new IllegalArgumentException("Attribute index '"+index+"' out of range (0 to "+this.data.getType().size()+".");
773
        }
774
        Object value = this.data.get(index);
775
        FeatureAttributeDescriptor attribute = type.getAttributeDescriptor(index);
776
        if (type.hasEvaluators()) {
777
          Evaluator eval = attribute.getEvaluator();
778
          if (eval != null) {
779
            if (value == null) { // Ya hemos calculado el campo ?
780
              // FIXME: para comprobar si esta calculado usar un array especifico.
781
              try {
782
                  value = eval.evaluate(this);
783
              } catch (EvaluatorException e) {
784
                  throw new DataEvaluatorRuntimeException(e);
785
              }
786
              this.data.set(index, value);
787
            }          
788
          }
789
        }
790
        value = get(attribute, value);
791
        return  value;
792
    }
793

    
794
    private Object get(FeatureAttributeDescriptor featureAttributeDescriptor, Object value){
795
        FeatureAttributeEmulator emulator = featureAttributeDescriptor.getFeatureAttributeEmulator();
796
        if( emulator != null ) {
797
//            int index = featureAttributeDescriptor.getIndex();
798
//            value = this.data.get(index);
799
//            if( value==null ) {
800
                value = emulator.get(this);
801
//                this.data.set(index,value);
802
//            }
803
        } else {
804
            FeatureAttributeGetter getter = featureAttributeDescriptor.getFeatureAttributeGetter();
805
            if( getter != null ) {
806
                value = getter.getter(value);
807
            }
808
        }
809
        if( featureAttributeDescriptor.getType()==DataTypes.GEOMETRY ) {
810
            if( value != null ) {
811
                Geometry geom = (Geometry)value;
812
                if( geom.getProjection()==null ) {
813
                    IProjection proj = ((DefaultFeatureAttributeDescriptor)featureAttributeDescriptor).getSRS(this.storeRef);
814
                    geom.setProjection(proj);
815
                }
816
            }
817
        }
818
        return value;
819
    }
820

    
821
    @Override
822
    public byte[] getByteArray(String name) {
823
        return this.getByteArray(this.data.getType().getIndex(name));
824
    }
825

    
826
    @Override
827
    public byte[] getByteArray(int index) {
828
        return (byte[]) this.get(index);
829
    }
830

    
831
    @Override
832
    public Object[] getArray(String name) {
833
        return this.getArray(this.data.getType().getIndex(name));
834
    }
835

    
836
    @Override
837
    public Object[] getArray(int index) {
838
        return (Object[]) this.get(index);
839
    }
840

    
841
    @Override
842
    public boolean getBoolean(String name) {
843
        return this.getBoolean(this.data.getType().getIndex(name));
844
    }
845

    
846
    @Override
847
    public boolean getBoolean(int index) {
848
        Boolean value = ((Boolean) this.get(index,Boolean.class,DataTypes.BOOLEAN));
849
        if (value == null) {
850
            return false;
851
        }
852
        return value;
853
    }
854

    
855
    @Override
856
    public byte getByte(String name) {
857
        return this.getByte(this.data.getType().getIndex(name));
858
    }
859

    
860
    @Override
861
    public byte getByte(int index) {
862
        Byte value = ((Byte) this.get(index,Byte.class,DataTypes.BYTE));
863
        if (value == null) {
864
            return 0;
865
        }
866
        return value;
867
    }
868

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

    
874
    @Override
875
    public Date getDate(int index) {
876
        Date value = ((Date) this.get(index,java.sql.Date.class,DataTypes.DATE));
877
        return value;
878
    }
879

    
880
    @Override
881
    public Date getTime(String name) {
882
        return this.getTime(this.data.getType().getIndex(name));
883
    }
884

    
885
    @Override
886
    public Date getTime(int index) {
887
        Date value = ((Date) this.get(index,java.sql.Time.class,DataTypes.TIME));
888
        return value;
889
    }
890

    
891
    @Override
892
    public Date getTimestamp(String name) {
893
        return this.getTimestamp(this.data.getType().getIndex(name));
894
    }
895

    
896
    @Override
897
    public Date getTimestamp(int index) {
898
        Date value = ((Date) this.get(index,java.sql.Timestamp.class,DataTypes.TIMESTAMP));
899
        return value;
900
    }
901

    
902
    @Override
903
    public double getDouble(String name) {
904
        return this.getDouble(this.data.getType().getIndex(name));
905
    }
906

    
907
    @Override
908
    public double getDouble(int index) {
909

    
910
        Double value = ((Double) this.get(index,Double.class,DataTypes.DOUBLE));
911
        if (value == null) {
912
            return 0;
913
        }
914
        return value;
915
    }
916

    
917
    @Override
918
    public BigDecimal getDecimal(String name) {
919
        return this.getDecimal(this.data.getType().getIndex(name));
920
    }
921

    
922
    @Override
923
    public BigDecimal getDecimal(int index) {
924
        BigDecimal value = ((BigDecimal) this.get(index,BigDecimal.class,DataTypes.DECIMAL));
925
        return value;
926
    }
927

    
928
    @Override
929
    public Feature getFeature(String name) {
930
        return this.getFeature(this.data.getType().getIndex(name));
931
    }
932

    
933
    @Override
934
    public Feature getFeature(int index) {
935
        return (Feature) this.get(index);
936
    }
937

    
938
    @Override
939
    public float getFloat(String name) {
940
        return this.getFloat(this.data.getType().getIndex(name));
941
    }
942

    
943
    @Override
944
    public float getFloat(int index) {
945
        Float value = ((Float) this.get(index,Float.class,DataTypes.FLOAT));
946
        if (value == null) {
947
            return 0;
948
        }
949
        return value;
950
    }
951

    
952
    @Override
953
    public Geometry getGeometry(String name) {
954
        return this.getGeometry(this.data.getType().getIndex(name));
955
    }
956

    
957
    @Override
958
    public Geometry getGeometry(int index) {
959
        return (Geometry) this.get(index,Geometry.class,DataTypes.GEOMETRY);
960
    }
961

    
962
    @Override
963
    public int getInt(String name) {
964
        return this.getInt(this.data.getType().getIndex(name));
965
    }
966

    
967
    @Override
968
    public int getInt(int index) {
969
        Integer value = ((Integer) this.get(index,Integer.class,DataTypes.INT));
970
        if (value == null) {
971
            return 0;
972
        }
973
        return value;
974
    }
975

    
976
    @Override
977
    public long getLong(String name) {
978
        return this.getLong(this.data.getType().getIndex(name));
979
    }
980

    
981
    @Override
982
    public long getLong(int index) {
983
        Long value = ((Long) this.get(index,Long.class,DataTypes.LONG));
984
        if (value == null) {
985
            return 0;
986
        }
987
        return value;
988
    }
989

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

    
995
    @Override
996
    public String getString(int index) {
997
        return (String) this.get(index,String.class,DataTypes.STRING);
998
    }
999

    
1000
    @Override
1001
    public Object getContextValue(String name) {
1002
        name = name.toLowerCase();
1003
        if (name.equals("store")) {
1004
            return this.getStore();
1005
        }
1006

    
1007
        if (name.equals("featuretype")) {
1008
            return this.data.getType();
1009
        }
1010

    
1011
        if (name.equals("feature")) {
1012
            return this;
1013
        }
1014

    
1015
        throw new IllegalArgumentException(name);
1016
    }
1017

    
1018
    @Override
1019
    public Iterator getDataNames() {
1020
        class DataNamesIterator implements Iterator {
1021
            Iterator attributeIteraror;
1022

    
1023
            DataNamesIterator(DefaultFeature feature) {
1024
                this.attributeIteraror = feature.getType().iterator();
1025
            }
1026

    
1027
            @Override
1028
            public boolean hasNext() {
1029
                return this.attributeIteraror.hasNext();
1030
            }
1031

    
1032
            @Override
1033
            public Object next() {
1034
                return ((FeatureAttributeDescriptor) this.attributeIteraror
1035
                        .next()).getName();
1036
            }
1037

    
1038
            @Override
1039
            public void remove() {
1040
                throw new UnsupportedOperationException();
1041
            }
1042

    
1043
        }
1044
        return new DataNamesIterator(this);
1045
    }
1046

    
1047
    @Override
1048
    public Object getDataValue(String name) {
1049
        name = name.toLowerCase();
1050
        try {
1051
            return get(name);
1052
        } catch (IllegalArgumentException ex) {
1053
            if( "defaultgeometry".equalsIgnoreCase(name )) {
1054
                return this.getDefaultGeometry();
1055
            }
1056
            throw ex;
1057
        }
1058
    }
1059

    
1060
    @Override
1061
    public Iterator getDataValues() {
1062
        class DataValuesIterator implements Iterator {
1063
            DefaultFeature feature;
1064
            int current = 0;
1065

    
1066
            DataValuesIterator(DefaultFeature feature) {
1067
                this.feature = feature;
1068
            }
1069

    
1070
            @Override
1071
            public boolean hasNext() {
1072
                return current < feature.getType().size() - 1;
1073
            }
1074

    
1075
            @Override
1076
            public Object next() {
1077
                return feature.get(current++);
1078
            }
1079

    
1080
            @Override
1081
            public void remove() {
1082
                throw new UnsupportedOperationException();
1083
            }
1084

    
1085
        }
1086
        return new DataValuesIterator(this);
1087
    }
1088

    
1089
    @Override
1090
    public boolean hasContextValue(String name) {
1091
        name = name.toLowerCase();
1092
        if (name.equals("store")) {
1093
            return true;
1094
        }
1095

    
1096
        if (name.equals("featuretype")) {
1097
            return true;
1098
        }
1099

    
1100
        return name.equals("feature");
1101
    }
1102

    
1103
    @Override
1104
    public boolean hasDataValue(String name) {
1105
        name = name.toLowerCase();
1106
        return this.data.getType().getIndex(name) >= 0;
1107
    }
1108

    
1109
//    @Override
1110
//    public Time getTime(int index) {
1111
//        return ((Time) this.get(index,Time.class,DataTypes.INSTANT));
1112
//    }
1113
//
1114
//    @Override
1115
//    public Time getTime(String name) {
1116
//        return this.getInstant(this.data.getType().getIndex(name));
1117
//    }
1118
//
1119
//    @Override
1120
//    public Instant getInstant(int index) {
1121
//        return ((Instant) this.get(index,Instant.class,DataTypes.INSTANT));
1122
//    }
1123
//
1124
//    @Override
1125
//    public Instant getInstant(String name) {
1126
//        return this.getInstant(this.data.getType().getIndex(name));
1127
//    }
1128
//
1129
//    @Override
1130
//    public Interval getInterval(int index) {
1131
//        return ((Interval) this.get(index,Interval.class,DataTypes.INTERVAL));
1132
//    }
1133
//
1134
//    @Override
1135
//    public Interval getInterval(String name) {
1136
//        return this.getInterval(this.data.getType().getIndex(name));
1137
//    }
1138
//
1139
    @Override
1140
    public DynObject getAsDynObject() {
1141
        DynObjectFeatureFacade facade = new DynObjectFeatureFacade(this);
1142
        return facade;
1143
    }
1144

    
1145
    @Override
1146
    public String toString() {
1147
            StringBuilder builder = new StringBuilder();
1148
        FeatureAttributeDescriptor[] attributeDescriptors =
1149
            getType().getAttributeDescriptors();
1150
        for (int i = 0; i < attributeDescriptors.length; i++) {
1151
            String name = attributeDescriptors[i].getName();
1152
            Object value = get(name);
1153
            builder.append(value);
1154
            if (i < attributeDescriptors.length - 1) {
1155
                builder.append(", ");
1156
            }
1157
        }
1158
        return builder.toString();
1159
    }
1160

    
1161

    
1162

    
1163

    
1164
        /**
1165
     * @return the inserted
1166
     */
1167
    public boolean isInserted() {
1168
        return inserted;
1169
    }
1170

    
1171

    
1172
    /**
1173
     * @param inserted the inserted to set
1174
     */
1175
    public void setInserted(boolean inserted) {
1176
        this.inserted = inserted;
1177
    }
1178

    
1179
        @Override
1180
    public EvaluatorData getEvaluatorData() {
1181
        return this;
1182
    }
1183

    
1184
    public int size() {
1185
        return this.data.getType().size();
1186
    }
1187
    
1188
    public boolean isEmpty() {
1189
        return false;
1190
    }
1191

    
1192
    public Iterator<String> iterator() {
1193
        final Iterator<FeatureAttributeDescriptor> x = this.data.getType().iterator();
1194
        return new Iterator<String>() {
1195
            @Override
1196
            public boolean hasNext() {
1197
                return x.hasNext();
1198
            }
1199

    
1200
            @Override
1201
            public String next() {
1202
                return x.next().getName();
1203
            }
1204
        };
1205
    }
1206
    
1207
    public boolean containsKey(String key) {
1208
        return this.data.getType().get(key)!=null;
1209
    }
1210

    
1211
    @Override
1212
    public String getLabelOfValue(String name) {
1213
        FeatureAttributeDescriptor attrdesc = this.data.getType().getAttributeDescriptor(name);
1214
        if( attrdesc==null ) {
1215
            throw new IllegalArgumentException("Attribute name '"+name+"' not found in the feature.");
1216
        }
1217
        Object value = this.get(attrdesc.getIndex());
1218
        String label = attrdesc.getLabelOfValue(value);
1219
        return label;
1220
    }
1221
   
1222
    @Override
1223
    public void setExtraValue(String name, Object value) {
1224
      if( this.extraValues==null ) {
1225
        this.extraValues = new HashMap<>();
1226
      }
1227
      this.extraValues.put(name, value);
1228
    }
1229

    
1230
    @Override
1231
    public Object getExtraValue(String name) {
1232
        Object value;
1233
        if( this.extraValues!=null ) {
1234
          if( this.extraValues.containsKey(name) ) {
1235
            return this.extraValues.get(name);
1236
          }
1237
        }
1238
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1239
        int index = columns.getIndexOf(name);
1240
        if( index >= 0 ) {
1241
          if( extraValuesData==null ) {
1242
            extraValuesData = new Object[columns.size()];
1243
            EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1244
            value = attrdesc.getFeatureAttributeEmulator().get(this);
1245
            extraValuesData[index] = value;
1246
          } else {
1247
            value = extraValuesData[index];
1248
            if( value == null ) {
1249
              EditableFeatureAttributeDescriptor attrdesc = columns.get(index);
1250
              value = attrdesc.getFeatureAttributeEmulator().get(this);
1251
              extraValuesData[index] = value;
1252
            }
1253
          }
1254
          return value;
1255
        }
1256
        value = this.data.getExtraValue(name);
1257
        return value;
1258
    }
1259

    
1260
    @Override
1261
    public boolean hasExtraValue(String name) {
1262
        if( this.extraValues!=null ) {
1263
          if( this.extraValues.containsKey(name) ) {
1264
            return true;
1265
          }
1266
        }
1267
        FeatureExtraColumns columns = this.getType().getExtraColumns();
1268
        int index = columns.getIndexOf(name);
1269
        if( index >= 0 ) {
1270
          return true;
1271
        }
1272
        return this.data.hasExtraValue(name);
1273
    }
1274
    
1275
    @Override
1276
    public Object getExtraValue(int index) {
1277
        return this.data.getExtraValue(index);
1278
    }
1279

    
1280
    public JsonObject toJSON() {
1281
        JsonObjectBuilder builder = Json.createObjectBuilder();
1282
        
1283
        FeatureType ft = this.getType();
1284
        for (FeatureAttributeDescriptor desc : ft) {
1285
            if (desc.isComputed()) {
1286
                continue;
1287
            }
1288
            switch(desc.getType()) {
1289
                case DataTypes.GEOMETRY:
1290
                    {
1291
                        try {
1292
                            builder.add(desc.getName(), this.getGeometry(desc.getIndex()).convertToWKT());
1293
                        } catch (Exception ex) {
1294
                            throw new RuntimeException("Can't convert geometry to WKT.", ex);
1295
                        }
1296
                    }
1297
                    break;
1298
                case DataTypes.BOOLEAN:
1299
                    builder.add(desc.getName(), this.getBoolean(desc.getIndex()));
1300
                    break;
1301
                case DataTypes.BYTE:
1302
                    builder.add(desc.getName(), this.getByte(desc.getIndex()));
1303
                    break;
1304
                case DataTypes.INT:
1305
                    builder.add(desc.getName(), this.getInt(desc.getIndex()));
1306
                    break;
1307
                case DataTypes.LONG:
1308
                    builder.add(desc.getName(), this.getLong(desc.getIndex()));
1309
                    break;
1310
                case DataTypes.DOUBLE:
1311
                    builder.add(desc.getName(), this.getDouble(desc.getIndex()));
1312
                    break;
1313
                case DataTypes.FLOAT:
1314
                    builder.add(desc.getName(), this.getFloat(desc.getIndex()));
1315
                    break;
1316
                case DataTypes.DATE:
1317
                    // Format date as ISO 8601
1318
                    Date date = this.getDate(desc.getIndex());
1319
                    String value = DateTimeFormatter.ISO_DATE_TIME.format(date.toInstant());
1320
                    builder.add(desc.getName(), value);
1321
                    break;
1322
                default:
1323
                    builder.add(desc.getName(), Objects.toString(this.get(desc.getIndex()),""));
1324
            }
1325
        }        
1326
        return builder.build();
1327
    }
1328

    
1329
    @Override
1330
    public List<String> getKeys() {
1331
      List<String> l = new ArrayList<>();
1332
      for (FeatureAttributeDescriptor descriptor : this.getType()) {
1333
        l.add(descriptor.getName());
1334
      }
1335
      return l;
1336
    }
1337

    
1338
}