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 / DefaultFeatureType.java @ 44753

History | View | Annotate | Download (39.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.io.File;
27
import java.lang.ref.WeakReference;
28
import java.util.ArrayList;
29
import java.util.Arrays;
30
import java.util.Collections;
31
import java.util.Date;
32
import java.util.HashSet;
33
import java.util.Iterator;
34
import java.util.LinkedHashSet;
35
import java.util.List;
36
import java.util.Objects;
37
import java.util.Set;
38
import java.util.function.Predicate;
39
import java.util.zip.CRC32;
40
import org.apache.commons.lang3.ArrayUtils;
41
import org.apache.commons.lang3.StringUtils;
42

    
43
import org.cresques.cts.IProjection;
44

    
45
import org.gvsig.fmap.dal.DataTypes;
46
import org.gvsig.fmap.dal.exception.DataException;
47
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
48
import org.gvsig.fmap.dal.feature.EditableFeatureType;
49
import org.gvsig.fmap.dal.feature.Feature;
50
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
51
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
52
import org.gvsig.fmap.dal.feature.FeatureExtraColumn;
53
import org.gvsig.fmap.dal.feature.FeatureRules;
54
import org.gvsig.fmap.dal.feature.FeatureStore;
55
import org.gvsig.fmap.dal.feature.FeatureType;
56
import org.gvsig.tools.ToolsLocator;
57
import org.gvsig.tools.dynobject.DynClass;
58
import org.gvsig.tools.dynobject.DynField;
59
import org.gvsig.tools.dynobject.DynMethod;
60
import org.gvsig.tools.dynobject.DynObject;
61
import org.gvsig.tools.dynobject.DynObjectValueItem;
62
import org.gvsig.tools.dynobject.DynStruct;
63
import org.gvsig.tools.dynobject.DynStruct_v2;
64
import org.gvsig.tools.dynobject.Tags;
65
import org.gvsig.tools.dynobject.exception.DynMethodException;
66
import org.gvsig.tools.dynobject.exception.DynObjectValidateException;
67
import org.gvsig.tools.dynobject.impl.DefaultTags;
68
import org.gvsig.tools.i18n.I18nManager;
69
import org.gvsig.tools.persistence.PersistenceManager;
70
import org.gvsig.tools.persistence.Persistent;
71
import org.gvsig.tools.persistence.PersistentState;
72
import org.gvsig.tools.persistence.exception.PersistenceException;
73

    
74
@SuppressWarnings("UseSpecificCatch")
75
public class DefaultFeatureType
76
        extends ArrayList<FeatureAttributeDescriptor>
77
        implements
78
        FeatureType,
79
        Persistent,
80
        DynClass,
81
        DynStruct_v2,
82
        org.gvsig.tools.lang.Cloneable {
83

    
84
    /**
85
     *
86
     */
87
    private static final long serialVersionUID = -7988721447349282215L;
88

    
89
    public static final RecentUsedsAttributesImpl RECENTS_USEDS = new RecentUsedsAttributesImpl();
90

    
91
    private DefaultFeatureRules rules;
92
    protected boolean hasEvaluators;
93
    protected boolean hasEmulators;
94
    protected String defaultGeometryAttributeName;
95
    protected String defaultTimeAttributeName;
96
    protected int defaultGeometryAttributeIndex;
97
    protected int defaultTimeAttributeIndex;
98
    private String id;
99
    protected boolean hasOID;
100
    protected boolean allowAtomaticValues;
101
    protected FeatureAttributeDescriptor[] pk = null;
102
    protected String internalID = null;
103

    
104
    private List srsList = null;
105
    private WeakReference storeRef;
106
    private boolean requiredFields;
107

    
108
    private String description;
109
    private String label;
110
    private Tags tags;
111
//    private List<FeatureAttributeDescriptor> descriptors;
112
    private FeatureExtraColumn extraColumn;
113

    
114
    public DefaultFeatureType() {
115
        // Usado en la persistencia.
116
        this.internalID = Integer.toHexString((int) (Math.random() * 100000)).toUpperCase();
117
        this.id = id = "default";
118
        this.rules = new DefaultFeatureRules();
119
        this.hasEvaluators = false;
120
        this.hasEmulators = false;
121
        this.defaultGeometryAttributeName = null;
122
        this.defaultTimeAttributeName = null;
123
        this.defaultGeometryAttributeIndex = -1;
124
        this.defaultTimeAttributeIndex = -1;
125
        this.allowAtomaticValues = false;
126
        this.tags = new DefaultTags();
127
        this.extraColumn = new DefaultFeatureExtraColumn();
128
    }
129

    
130
    protected DefaultFeatureType(FeatureStore store, String id) {
131
        this();
132
        if (StringUtils.isEmpty(id)) {
133
            id = "default";
134
        }
135
        this.id = id;
136
        setStore(store);
137
    }
138

    
139
    protected DefaultFeatureType(FeatureStore store) {
140
        this(store, (String) null);
141
    }
142

    
143
    protected DefaultFeatureType(DefaultFeatureType other) {
144
        this(other.getStore(), (String) null);
145
        copyFrom(other, true);
146
    }
147

    
148
    protected DefaultFeatureType(DefaultFeatureType other,
149
            boolean copyAttributes) {
150
        this(other.getStore(), (String) null);
151
        this.copyFrom(other, copyAttributes);
152
    }
153

    
154
    @Override
155
    public void copyFrom(FeatureType other) {
156
        String internalIDSaved = this.internalID;
157
        String idSaved = this.id;
158
        copyFrom((DefaultFeatureType) other, true);
159
        this.id = idSaved;
160
        this.internalID = internalIDSaved;
161
    }
162
    
163
    protected void addAll(FeatureType attributes) {
164
        for (FeatureAttributeDescriptor attribute : attributes) {
165
            DefaultFeatureAttributeDescriptor copy = this.getCopyAttributeDescriptor((DefaultFeatureAttributeDescriptor) attribute);
166
            super.add(copy);
167
        }
168
        DefaultFeatureType ft = (DefaultFeatureType) attributes; 
169
        this.pk = null;
170
        this.defaultGeometryAttributeName = ft.defaultGeometryAttributeName;
171
        this.defaultTimeAttributeName = ft.defaultTimeAttributeName;
172
        this.defaultGeometryAttributeIndex = ft.defaultGeometryAttributeIndex;
173
        this.defaultTimeAttributeIndex = ft.defaultTimeAttributeIndex;
174
    }
175
    
176
    protected void copyFrom(DefaultFeatureType other, boolean copyAttributes) {
177
        this.id = other.getId();
178
        if (copyAttributes) {
179
            this.addAll((FeatureType)other);
180
        }
181
        this.defaultGeometryAttributeName = other.defaultGeometryAttributeName;
182
        this.defaultTimeAttributeName = other.defaultTimeAttributeName;
183
        this.defaultGeometryAttributeIndex = other.defaultGeometryAttributeIndex;
184
        this.defaultTimeAttributeIndex = other.defaultTimeAttributeIndex;
185

    
186
        this.hasEvaluators = other.hasEvaluators;
187
        this.hasEmulators = other.hasEmulators;
188
        this.rules = (DefaultFeatureRules) other.rules.getCopy();
189
        this.hasOID = other.hasOID;
190
        this.id = other.id; // XXX ???? copiar o no esto????
191
        this.internalID = other.internalID;
192
        this.label = other.label;
193
        this.description = other.description;
194
        try {
195
            this.tags = (Tags) other.tags.clone();
196
        } catch (CloneNotSupportedException ex) {
197
            
198
        }
199
    }
200
    
201
    protected DefaultFeatureAttributeDescriptor getCopyAttributeDescriptor(DefaultFeatureAttributeDescriptor src) {
202
        DefaultFeatureAttributeDescriptor copy = new DefaultFeatureAttributeDescriptor(src);
203
        copy.setFeatureType(this);
204
        return copy;
205
    }
206

    
207
    @Override
208
    public String getId() {
209
        return this.id;
210
    }
211

    
212
    @Override
213
    public Object get(String name) {
214
        FeatureAttributeDescriptor attr;
215
        Iterator iter = this.iterator();
216
        while (iter.hasNext()) {
217
            attr = (FeatureAttributeDescriptor) iter.next();
218
            if (attr.getName().equalsIgnoreCase(name)) {
219
                return attr;
220
            }
221
        }
222
        return null;
223
    }
224

    
225
    @Override
226
    public FeatureAttributeDescriptor getAttributeDescriptor(String name) {
227
        FeatureAttributeDescriptor attr;
228
        Iterator iter = this.iterator();
229
        while (iter.hasNext()) {
230
            attr = (FeatureAttributeDescriptor) iter.next();
231
            if (attr.getName().equalsIgnoreCase(name)) {
232
                return attr;
233
            }
234
        }
235
        return null;
236
    }
237

    
238
    @Override
239
    public FeatureAttributeDescriptor getAttributeDescriptor(int index) {
240
        return (FeatureAttributeDescriptor) super.get(index);
241
    }
242

    
243
    @Override
244
    public String getAttributeName(int index) {
245
      try {
246
        return super.get(index).getName();
247
      } catch(Exception ex) {
248
        return null;
249
      }
250
    }
251

    
252
    @Override
253
    public FeatureType getCopy() {
254
        return new DefaultFeatureType(this);
255
    }
256

    
257
    @Override
258
    public Object clone() {
259
        return this.getCopy();
260
    }
261

    
262
    @Override
263
    public int getDefaultGeometryAttributeIndex() {
264
        return this.defaultGeometryAttributeIndex;
265
    }
266

    
267
    @Override
268
    public String getDefaultGeometryAttributeName() {
269
        return this.defaultGeometryAttributeName;
270
    }
271

    
272
    @Override
273
    public int getDefaultTimeAttributeIndex() {
274
        return this.defaultTimeAttributeIndex;
275
    }
276

    
277
    @Override
278
    public String getDefaultTimeAttributeName() {
279
        return this.defaultTimeAttributeName;
280
    }
281

    
282
    @Override
283
    public EditableFeatureType getEditable() {
284
        return new DefaultEditableFeatureType(this);
285
    }
286

    
287
    @Override
288
    public int getIndex(String name) {
289
        FeatureAttributeDescriptor attr;
290
        Iterator iter = this.iterator();
291
        while (iter.hasNext()) {
292
            attr = (FeatureAttributeDescriptor) iter.next();
293
            if (attr.getName().equalsIgnoreCase(name)) {
294
                return attr.getIndex();
295
            }
296
        }
297
        return -1;
298
    }
299

    
300
    @Override
301
    public FeatureRules getRules() {
302
        return this.rules;
303
    }
304

    
305
    @Override
306
    public boolean hasEvaluators() {
307
        return this.hasEvaluators;
308
    }
309

    
310
    public boolean hasEmulators() {
311
        return this.hasEmulators;
312
    }
313

    
314
    public boolean hasRequiredFields() {
315
        return this.requiredFields;
316
    }
317

    
318
    @Override
319
    public List getSRSs() {
320
        if (this.srsList == null) {
321
            ArrayList tmp = new ArrayList();
322
            Iterator iter = iterator();
323
            Iterator tmpIter;
324
            boolean allreadyHave;
325
            IProjection tmpSRS;
326
            FeatureAttributeDescriptor attr;
327
            while (iter.hasNext()) {
328
                attr = (FeatureAttributeDescriptor) iter.next();
329
                if (attr.getDataType().getType() == DataTypes.GEOMETRY
330
                        && attr.getSRS() != null) {
331
                    allreadyHave = false;
332
                    tmpIter = tmp.iterator();
333
                    while (tmpIter.hasNext()) {
334
                        tmpSRS = (IProjection) tmpIter.next();
335
                        if (tmpSRS.getAbrev().equals(attr.getSRS().getAbrev())) {
336
                            allreadyHave = true;
337
                            break;
338
                        }
339
                    }
340
                    if (!allreadyHave) {
341
                        tmp.add(attr.getSRS());
342
                    }
343
                }
344
            }
345
            this.srsList = Collections.unmodifiableList(tmp);
346
        }
347
        return this.srsList;
348
    }
349

    
350
    @Override
351
    public IProjection getDefaultSRS() {
352
        if (this.getDefaultGeometryAttributeIndex() < 0) {
353
            return null;
354
        }
355
        return this.getAttributeDescriptor(
356
                this.getDefaultGeometryAttributeIndex()).getSRS();
357
    }
358

    
359
    public void validateFeature(Feature feature, int mode) throws DataException {
360
        DefaultFeatureRules rules = (DefaultFeatureRules) this.getRules();
361
        rules.validate(feature, mode);
362
    }
363

    
364
    public FeatureType getSubtype() throws DataException {
365
        return new SubtypeFeatureType(this, null, null, true);
366
    }
367

    
368
    public FeatureType getSubtype(String[] names) throws DataException {
369
        return this.getSubtype(names, null, true);
370
    }
371

    
372
    public FeatureType getSubtype(String[] names, String[] constantsNames) throws DataException {
373
        return this.getSubtype(names, constantsNames, true);
374
    }
375

    
376
    public FeatureType getSubtype(String[] names, String[] constantsNames, boolean includePk) throws DataException {
377
        if (ArrayUtils.isEmpty(names) && ArrayUtils.isEmpty(constantsNames)) {
378
            return (FeatureType) this.clone();
379
        }
380
        return new SubtypeFeatureType(this, names, constantsNames,includePk);
381
    }
382

    
383
    public boolean isSubtypeOf(FeatureType featureType) {
384
        return false;
385
    }
386

    
387
    @Override
388
    public List<FeatureAttributeDescriptor> toList() {
389
        return Collections.unmodifiableList(this);
390
    }
391

    
392
    @Override
393
    public Tags getTags() {
394
        return this.tags;
395
    }
396

    
397
    @Override
398
    public String getLabel() {
399
        return this.label;
400
    }
401

    
402
    @Override
403
    public void setLabel(String label) {
404
        this.label = label;
405
    }
406

    
407
    @Override
408
    public DynField addDynField(String name, int type) {
409
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
410
    }
411

    
412
    @Override
413
    public FeatureExtraColumn getExtraColumn() {
414
        return extraColumn;
415
    }
416
    
417
    public void setExtraColumn(FeatureExtraColumn extraColumn) { //List<FeatureAttributeDescriptor> descriptors) {
418
          this.extraColumn = extraColumn;
419
    }
420

    
421
    class SubtypeFeatureType extends DefaultFeatureType {
422

    
423
        /**
424
         *
425
         */
426
        private static final long serialVersionUID = 6913732960073922540L;
427
        WeakReference parent;
428

    
429
        SubtypeFeatureType(DefaultFeatureType parent, String[] names, String[] constantsNames, boolean includePk)
430
                throws DataException {
431
            super(parent, false);
432
            DefaultFeatureAttributeDescriptor attrcopy;
433
            Set<String> attrnames = new LinkedHashSet<>();
434
            Set<String> requiredAttrnames = new HashSet<>();
435

    
436
            if (ArrayUtils.isEmpty(names)) {
437
                for (FeatureAttributeDescriptor attrdesc : parent) {
438
                    attrnames.add(attrdesc.getName().toLowerCase());
439
                }
440
            } else { 
441
                attrnames.addAll(Arrays.asList(names));
442
                requiredAttrnames.addAll(Arrays.asList(names));
443
            }
444
            // Add required fields for emulated fields
445
            if (parent.hasEmulators) {
446
                // Ojo, este bucle falla cuando hay un campo calculado que depende
447
                // de otro campo calculado.
448
                for (FeatureAttributeDescriptor attrdesc : parent) {
449
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
450
                    if (emulator != null && attrnames.contains(attrdesc.getName().toLowerCase())) {
451
                        String theNames[] = emulator.getRequiredFieldNames();
452
                        if (names != null) {
453
                            for (String name : theNames) {
454
                                name = name.toLowerCase();
455
                                attrnames.add(name);
456
                                requiredAttrnames.add(name);
457
                            }
458
                        }
459
                    }
460
                }
461
            }
462
            // Add missing pk fiels
463
            if (includePk && !parent.hasOID()) {
464
                for (FeatureAttributeDescriptor attrdesc : parent) {
465
                    if (attrdesc.isPrimaryKey()) {
466
                        String name = attrdesc.getName().toLowerCase();
467
                        attrnames.add(name);
468
                        requiredAttrnames.add(name);
469
                    }
470
                }
471
            }
472

    
473
            // Copy attributes
474
            int i = 0;
475
            for (String name : attrnames) {
476
                DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) parent.get(name);
477
                if (attr == null) {
478
                    throw new SubtypeFeatureTypeNameException(name, parent.getId());
479
                }
480
                attrcopy = new DefaultFeatureAttributeDescriptor(attr);
481
                this.add(attrcopy);
482
                attrcopy.index = i++;
483
            }
484

    
485
            // Set the constants attributes.
486
            if (!ArrayUtils.isEmpty(constantsNames)) {
487
                for (String name : constantsNames) {
488
                    if (!requiredAttrnames.contains(name.toLowerCase())) {
489
                        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
490
                        attr.setConstantValue(true);
491
                    }
492
                }
493
            }
494

    
495
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
496
            if (this.defaultGeometryAttributeIndex < 0) {
497
                this.defaultGeometryAttributeName = null;
498
            }
499
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
500
            if (this.defaultTimeAttributeIndex < 0) {
501
                this.defaultTimeAttributeName = null;
502
            }
503
            this.parent = new WeakReference(parent);
504
        }
505

    
506
        public FeatureType getSubtype(String[] names, boolean includePk) throws DataException {
507
            return new SubtypeFeatureType((DefaultFeatureType) this.parent
508
                    .get(), names, null, includePk);
509
        }
510

    
511
        public boolean isSubtypeOf(FeatureType featureType) {
512
            if (featureType == null) {
513
                return false;
514
            }
515
            FeatureType parent = (FeatureType) this.parent.get();
516
            return featureType.equals(parent);
517
        }
518

    
519
        public EditableFeatureType getEditable() {
520
            throw new UnsupportedOperationException();
521
        }
522
    }
523

    
524
    public class SubtypeFeatureTypeNameException extends DataException {
525

    
526
        /**
527
         *
528
         */
529
        private static final long serialVersionUID = -4414242486723260101L;
530
        private final static String MESSAGE_FORMAT = "Attribute name '%(name)' not found in type (%(type)).";
531
        private final static String MESSAGE_KEY = "_SubtypeFeatureTypeNameException";
532

    
533
        public SubtypeFeatureTypeNameException(String name, String type) {
534
            super(MESSAGE_FORMAT, MESSAGE_KEY, serialVersionUID);
535
            setValue("name", name);
536
            setValue("type", type);
537
        }
538
    }
539

    
540
    public boolean hasOID() {
541
        return hasOID;
542
    }
543

    
544
    @Override
545
    public String toString() {
546
        StringBuffer s = new StringBuffer();
547
        s.append(this.getId());
548
        s.append(":[");
549
        String attName;
550
        for (int i = 0; i < size(); i++) {
551
            attName = ((FeatureAttributeDescriptor) get(i)).getName().toString();
552
            s.append(attName);
553
            if (i < size() - 1) {
554
                s.append(',');
555
            }
556
        }
557
        s.append(']');
558
        return s.toString();
559
    }
560

    
561
    @Override
562
    public Iterator<FeatureAttributeDescriptor> iterator() {
563
        return getIterator(super.iterator());
564
    }
565

    
566
    protected Iterator getIterator(Iterator iter) {
567
        return new DelegatedIterator(iter);
568
    }
569

    
570
    protected class DelegatedIterator implements Iterator {
571

    
572
        protected Iterator iterator;
573

    
574
        public DelegatedIterator(Iterator iter) {
575
            this.iterator = iter;
576
        }
577

    
578
        @Override
579
        public boolean hasNext() {
580
            return iterator.hasNext();
581
        }
582

    
583
        @Override
584
        public Object next() {
585
            return iterator.next();
586
        }
587

    
588
        @Override
589
        public void remove() {
590
            throw new UnsupportedOperationException();
591
        }
592

    
593
    }
594

    
595
    @Override
596
    public boolean allowAutomaticValues() {
597
        return this.allowAtomaticValues;
598
    }
599

    
600
    @Override
601
    public FeatureAttributeDescriptor[] getAttributeDescriptors() {
602
        return (FeatureAttributeDescriptor[]) super
603
                .toArray(new FeatureAttributeDescriptor[super.size()]);
604
    }
605

    
606
    @Override
607
    public boolean hasPrimaryKey() {
608
        if( pk!=null ) {
609
            return pk.length>0;
610
        }
611
        for (FeatureAttributeDescriptor attr : this) {
612
            if( attr.isPrimaryKey() ) {
613
                return true;
614
            }
615
        }
616
        return false;
617
    }
618

    
619
    @Override
620
    public boolean supportReferences() {
621
        return this.hasOID() || this.hasPrimaryKey();
622
    }
623
    
624
    @Override
625
    public FeatureAttributeDescriptor[] getPrimaryKey() {
626
        if (pk == null) {
627
            List pks = new ArrayList();
628
            Iterator iter = super.iterator();
629
            FeatureAttributeDescriptor attr;
630
            while (iter.hasNext()) {
631
                attr = (FeatureAttributeDescriptor) iter.next();
632
                if (attr.isPrimaryKey()) {
633
                    pks.add(attr);
634
                }
635
            }
636
            if (pks.isEmpty()) {
637
                pk = new FeatureAttributeDescriptor[0];
638
            } else {
639
                pk = (FeatureAttributeDescriptor[]) pks.toArray(new FeatureAttributeDescriptor[pks.size()]);
640
            }
641
        }
642
        return pk;
643
    }
644

    
645
    public FeatureAttributeDescriptor getDefaultGeometryAttribute() {
646
        if (this.defaultGeometryAttributeIndex < 0) {
647
            return null;
648
        }
649
        return (FeatureAttributeDescriptor) super
650
                .get(this.defaultGeometryAttributeIndex);
651
    }
652

    
653
    @Override
654
    public boolean equals(Object o) {
655
        if (this == o) {
656
            return true;
657
        }
658
        if (!(o instanceof DefaultFeatureType)) {
659
            return false;
660
        }
661
        DefaultFeatureType other = (DefaultFeatureType) o;
662
        if (!this.id.equals(other.id)) {
663
            return false;
664
        }
665
        if (this.size() != other.size()) {
666
            return false;
667
        }
668
        FeatureAttributeDescriptor attr, attrOther;
669
        Iterator iter, iterOther;
670
        iter = this.iterator();
671
        iterOther = other.iterator();
672
        while (iter.hasNext()) {
673
            attr = (FeatureAttributeDescriptor) iter.next();
674
            attrOther = (FeatureAttributeDescriptor) iterOther.next();
675
            if (!attr.equals(attrOther)) {
676
                return false;
677
            }
678
        }
679

    
680
        if (!StringUtils.equals(defaultGeometryAttributeName, other.defaultGeometryAttributeName)) {
681
            return false;
682
        }
683
        if (!StringUtils.equals(defaultTimeAttributeName, other.defaultTimeAttributeName)) {
684
            return false;
685
        }
686
        return true;
687

    
688
    }
689

    
690
    /**
691
     * Start of DynClass interface implementation READONLY
692
     */
693
    @Override
694
    public DynField addDynField(String name) {
695
        throw new UnsupportedOperationException();
696
    }
697

    
698
    @Override
699
    public DynField getDeclaredDynField(String name) {
700
        return (DynField) getAttributeDescriptor(name);
701
    }
702

    
703
    @Override
704
    public DynField[] getDeclaredDynFields() {
705
        return (DynField[]) getAttributeDescriptors();
706
    }
707

    
708
    @Override
709
    public String getDescription() {
710
        return this.description;
711
    }
712

    
713
    @Override
714
    public DynField getDynField(String name) {
715
        return (DynField) getAttributeDescriptor(name);
716
    }
717

    
718
    @Override
719
    public DynField[] getDynFields() {
720
        return (DynField[]) getAttributeDescriptors();
721
    }
722

    
723
    @Override
724
    public String getName() {
725
        return this.id + "_" + internalID;
726
    }
727

    
728
    @Override
729
    public void removeDynField(String name) {
730
        throw new UnsupportedOperationException();
731

    
732
    }
733

    
734
    @Override
735
    public void addDynMethod(DynMethod dynMethod) {
736
        throw new UnsupportedOperationException();
737

    
738
    }
739

    
740
    public void extend(DynClass dynClass) {
741
        throw new UnsupportedOperationException();
742

    
743
    }
744

    
745
    @Override
746
    public void extend(String dynClassName) {
747
        throw new UnsupportedOperationException();
748

    
749
    }
750

    
751
    @Override
752
    public void extend(String namespace, String dynClassName) {
753
        throw new UnsupportedOperationException();
754

    
755
    }
756

    
757
    @Override
758
    public DynMethod getDeclaredDynMethod(String name)
759
            throws DynMethodException {
760
        return null;
761
    }
762

    
763
    @Override
764
    public DynMethod[] getDeclaredDynMethods() throws DynMethodException {
765
        return null;
766
    }
767

    
768
    @Override
769
    public DynMethod getDynMethod(String name) throws DynMethodException {
770
        return null;
771
    }
772

    
773
    @Override
774
    public DynMethod getDynMethod(int code) throws DynMethodException {
775
        return null;
776
    }
777

    
778
    @Override
779
    public DynMethod[] getDynMethods() throws DynMethodException {
780
        return null;
781
    }
782

    
783
    @Override
784
    public DynClass[] getSuperDynClasses() {
785
        return null;
786
    }
787

    
788
    @Override
789
    public boolean isInstance(DynObject dynObject) {
790
        if (dynObject.getDynClass().getName() == getName()) {
791
            return true;
792
        }
793
        return false;
794
    }
795

    
796
    @Override
797
    public DynObject newInstance() {
798

    
799
        throw new UnsupportedOperationException();
800
    }
801

    
802
    @Override
803
    public void removeDynMethod(String name) {
804
        throw new UnsupportedOperationException();
805

    
806
    }
807

    
808
    @Override
809
    public DynField addDynFieldChoice(String name, int type,
810
            Object defaultValue, DynObjectValueItem[] values,
811
            boolean mandatory, boolean persistent) {
812
        throw new UnsupportedOperationException();
813
    }
814

    
815
    @Override
816
    public DynField addDynFieldRange(String name, int type,
817
            Object defaultValue, Object min, Object max, boolean mandatory,
818
            boolean persistent) {
819
        throw new UnsupportedOperationException();
820
    }
821

    
822
    @Override
823
    public DynField addDynFieldSingle(String name, int type,
824
            Object defaultValue, boolean mandatory, boolean persistent) {
825
        throw new UnsupportedOperationException();
826
    }
827

    
828
    @Override
829
    public void validate(DynObject object) throws DynObjectValidateException {
830
        //FIXME: not sure it's the correct code
831
        if (object instanceof Feature) {
832
            Feature fea = (Feature) object;
833
            if (fea.getType().equals(this)) {
834
                return;
835
            }
836
        }
837
        throw new DynObjectValidateException(this.id);
838
    }
839

    
840
    @Override
841
    public DynField addDynFieldLong(String name) {
842
        throw new UnsupportedOperationException();
843
    }
844

    
845
    @Override
846
    public DynField addDynFieldChoice(String name, int type,
847
            Object defaultValue, DynObjectValueItem[] values) {
848
        throw new UnsupportedOperationException();
849
    }
850

    
851
    @Override
852
    public DynField addDynFieldRange(String name, int type,
853
            Object defaultValue, Object min, Object max) {
854
        throw new UnsupportedOperationException();
855
    }
856

    
857
    @Override
858
    public DynField addDynFieldSingle(String name, int type, Object defaultValue) {
859
        throw new UnsupportedOperationException();
860
    }
861

    
862
    @Override
863
    public DynField addDynFieldString(String name) {
864
        throw new UnsupportedOperationException();
865
    }
866

    
867
    @Override
868
    public DynField addDynFieldInt(String name) {
869
        throw new UnsupportedOperationException();
870
    }
871

    
872
    @Override
873
    public DynField addDynFieldDouble(String name) {
874
        throw new UnsupportedOperationException();
875
    }
876

    
877
    @Override
878
    public DynField addDynFieldFloat(String name) {
879
        throw new UnsupportedOperationException();
880
    }
881

    
882
    public DynField addDynFieldBoolean(String name) {
883
        throw new UnsupportedOperationException();
884
    }
885

    
886
    @Override
887
    public DynField addDynFieldList(String name) {
888
        throw new UnsupportedOperationException();
889
    }
890

    
891
    @Override
892
    public DynField addDynFieldMap(String name) {
893
        throw new UnsupportedOperationException();
894
    }
895

    
896
    @Override
897
    public DynField addDynFieldObject(String name) {
898
        throw new UnsupportedOperationException();
899
    }
900

    
901
    @Override
902
    public DynField addDynFieldSet(String name) {
903
        throw new UnsupportedOperationException();
904
    }
905

    
906
    @Override
907
    public DynField addDynFieldArray(String name) {
908
        throw new UnsupportedOperationException();
909
    }
910

    
911
    @Override
912
    public DynField addDynFieldDate(String name) {
913
        throw new UnsupportedOperationException();
914
    }
915

    
916
    @Override
917
    public void extend(DynStruct struct) {
918
        throw new UnsupportedOperationException();
919
    }
920

    
921
    @Override
922
    public String getFullName() {
923
        // TODO: usar el DynClassName
924
        return this.id;
925
    }
926

    
927
    @Override
928
    public String getNamespace() {
929
        return "DALFeature";
930
    }
931

    
932
    @Override
933
    public DynStruct[] getSuperDynStructs() {
934
        return null;
935
    }
936

    
937
    @Override
938
    public void setDescription(String description) {
939
        this.description = description;
940
    }
941

    
942
    @Override
943
    public void setNamespace(String namespace) {
944
        throw new UnsupportedOperationException();
945
    }
946

    
947
    @Override
948
    public DynField addDynFieldFile(String name) {
949
        throw new UnsupportedOperationException();
950
    }
951

    
952
    @Override
953
    public DynField addDynFieldFolder(String name) {
954
        throw new UnsupportedOperationException();
955
    }
956

    
957
    @Override
958
    public DynField addDynFieldURL(String name) {
959
        throw new UnsupportedOperationException();
960
    }
961

    
962
    @Override
963
    public DynField addDynFieldURI(String name) {
964
        throw new UnsupportedOperationException();
965
    }
966

    
967
    @Override
968
    public boolean isExtendable(DynStruct dynStruct) {
969
        return false;
970
    }
971

    
972
    public void extend(DynStruct[] structs) {
973
        // TODO Auto-generated method stub
974

    
975
    }
976

    
977
    @Override
978
    public void remove(DynStruct superDynStruct) {
979
        // TODO Auto-generated method stub
980

    
981
    }
982

    
983
    public void removeAll(DynStruct[] superDynStruct) {
984
        // TODO Auto-generated method stub
985

    
986
    }
987

    
988
    @Override
989
    public FeatureAttributeDescriptor getDefaultTimeAttribute() {
990
        if (this.defaultTimeAttributeIndex < 0) {
991
            return null;
992
        }
993
        return (FeatureAttributeDescriptor) super
994
                .get(this.defaultTimeAttributeIndex);
995
    }
996

    
997
    public void setDefaultTimeAttributeName(String name) {
998
        if (name == null || name.length() == 0) {
999
            this.defaultTimeAttributeIndex = -1;
1000
            return;
1001
        }
1002
        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
1003
        if (attr == null) {
1004
            throw new IllegalArgumentException("Attribute '" + name + "' not found.");
1005
        }
1006
        if (attr.getIndex() < 0) {
1007
            fixAll();
1008
        }
1009
        this.defaultTimeAttributeIndex = attr.getIndex();
1010
    }
1011

    
1012
    protected void fixAll() {
1013
        int i = 0;
1014
        Iterator iter = super.iterator();
1015
        DefaultFeatureAttributeDescriptor attr;
1016

    
1017
        while (iter.hasNext()) {
1018
            attr = (DefaultFeatureAttributeDescriptor) iter.next();
1019
            if (attr.getOder() < 1) {
1020
                attr.setOrder(i * 10);
1021
            }
1022
            attr.setIndex(i++);
1023
            attr.fixAll();
1024
            if (attr.getEvaluator() != null) {
1025
                this.hasEvaluators = true;
1026
            }
1027
            if (attr.getFeatureAttributeEmulator() != null) {
1028
                this.hasEmulators = true;
1029
                String[] x = attr.getFeatureAttributeEmulator().getRequiredFieldNames();
1030
                if (!ArrayUtils.isEmpty(x)) {
1031
                    this.requiredFields = true;
1032
                }
1033
            }
1034
            switch (attr.getType()) {
1035
                case DataTypes.GEOMETRY:
1036
                    if (this.defaultGeometryAttributeName == null) {
1037
                        this.defaultGeometryAttributeName = attr.getName();
1038
                    }
1039
                    break;
1040
                case DataTypes.INSTANT:
1041
                case DataTypes.INTERVAL:
1042
                case DataTypes.DATE:
1043
                    if (this.defaultTimeAttributeName == null && attr.isTime()) {
1044
                        this.defaultTimeAttributeName = attr.getName();
1045
                    }
1046
                    break;
1047
            }
1048
        }
1049
        if (this.defaultGeometryAttributeName != null) {
1050
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
1051
        }
1052
        if (this.defaultTimeAttributeName != null) {
1053
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
1054
        }
1055
        this.internalID = Long.toHexString(this.getCRC());
1056

    
1057
    }
1058

    
1059
    protected long getCRC() {
1060
        StringBuffer buffer = new StringBuffer();
1061
        for (int i = 0; i < this.size(); i++) {
1062
            FeatureAttributeDescriptor x = this.getAttributeDescriptor(i);
1063
            buffer.append(x.getName());
1064
            buffer.append(x.getDataTypeName());
1065
            buffer.append(x.getSize());
1066
        }
1067
        CRC32 crc = new CRC32();
1068
        byte[] data = buffer.toString().getBytes();
1069
        crc.update(data);
1070
        return crc.getValue();
1071
    }
1072

    
1073
    @Override
1074
    public FeatureStore getStore() {
1075
        if (this.storeRef == null) {
1076
            return null;
1077
        }
1078
        return (FeatureStore) this.storeRef.get();
1079
    }
1080

    
1081
    public void setStore(FeatureStore store) {
1082
        if (store == null) {
1083
            this.storeRef = null;
1084
        } else {
1085
            this.storeRef = new WeakReference(store);
1086
        }
1087
    }
1088

    
1089
    @Override
1090
    public List<FeatureAttributeDescriptor> getFilteredAttributes(
1091
            Predicate<FeatureAttributeDescriptor> filter,
1092
            int max
1093
    ) {
1094
        List<FeatureAttributeDescriptor> attrs = new ArrayList<>();
1095
        for (FeatureAttributeDescriptor attribute : this) {
1096
            if (filter.test(attribute)) {
1097
                attrs.add(attribute);
1098
            }
1099
        }
1100
        return attrs;
1101
    }
1102
    
1103
    @Override
1104
    public List<FeatureAttributeDescriptor> getRecentUseds() {
1105
        return RECENTS_USEDS.getAttributes(this);
1106
    }
1107
    
1108
    @Override
1109
    public void loadFromState(PersistentState state)
1110
            throws PersistenceException {
1111

    
1112
//        FIXME: rules
1113
        hasEvaluators = state.getBoolean("hasEvaluators");
1114
        hasEmulators = state.getBoolean("hasEmulators");
1115
        defaultGeometryAttributeName = state.getString("defaultGeometryAttributeName");
1116
        defaultTimeAttributeName = state.getString("defaultTimeAttributeName");
1117
        defaultGeometryAttributeIndex = state.getInt("defaultGeometryAttributeIndex");
1118
        defaultTimeAttributeIndex = state.getInt("defaultTimeAttributeIndex");
1119
        id = state.getString("id");
1120
        hasOID = state.getBoolean("hasOID");
1121
        allowAtomaticValues = state.getBoolean("allowAtomaticValues");
1122

    
1123
        requiredFields = state.getBoolean("requiredFields");
1124
        internalID = state.getString("internalID");
1125
        tags = (Tags) state.get("tags");
1126
        if( tags == null ) {
1127
            this.tags = new DefaultTags();
1128
        }
1129

    
1130
        List<FeatureAttributeDescriptor> elements = state.getList("elements");
1131
        for (FeatureAttributeDescriptor element : elements) {
1132
            ((DefaultFeatureAttributeDescriptor) element).setFeatureType(this);
1133
            super.add(element);
1134
        }
1135
        this.pk = null;
1136
        this.fixAll();
1137
    }
1138

    
1139
    @Override
1140
    public void saveToState(PersistentState state) throws PersistenceException {
1141

    
1142
//        FIXME: rules
1143
        state.set("hasEvaluators", hasEvaluators);
1144
        state.set("hasEmulators", hasEmulators);
1145
        state.set("defaultGeometryAttributeName", defaultGeometryAttributeName);
1146
        state.set("defaultTimeAttributeName", defaultTimeAttributeName);
1147
        state.set("defaultGeometryAttributeIndex", defaultGeometryAttributeIndex);
1148
        state.set("defaultTimeAttributeIndex", defaultTimeAttributeIndex);
1149
        state.set("id", id);
1150
        state.set("hasOID", hasOID);
1151
        state.set("allowAtomaticValues", allowAtomaticValues);
1152

    
1153
        state.set("requiredFields", requiredFields);
1154
        state.set("internalID", internalID);
1155

    
1156
        List<FeatureAttributeDescriptor> elements = new ArrayList<>();
1157
        elements.addAll(this);
1158
        state.set("elements", elements);
1159
        state.set("tags", tags);
1160

    
1161
    }
1162

    
1163
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1164

    
1165
    public static void registerPersistenceDefinition() {
1166
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1167

    
1168
        if (manager.getDefinition(FEATTYPE_PERSISTENCE_DEFINITION_NAME)
1169
                == null) {
1170
            DynStruct definition = manager.addDefinition(DefaultFeatureType.class,
1171
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME,
1172
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME
1173
                    + " persistent definition",
1174
                    null,
1175
                    null
1176
            );
1177
//            definition.addDynFieldObject("rules");
1178
            definition.addDynFieldBoolean("hasEvaluators");
1179
            definition.addDynFieldBoolean("hasEmulators");
1180
            definition.addDynFieldString("defaultGeometryAttributeName");
1181
            definition.addDynFieldString("defaultTimeAttributeName");
1182
            definition.addDynFieldInt("defaultGeometryAttributeIndex");
1183
            definition.addDynFieldInt("defaultTimeAttributeIndex");
1184
            definition.addDynFieldString("id");
1185
            definition.addDynFieldBoolean("hasOID");
1186
            definition.addDynFieldBoolean("allowAtomaticValues");
1187

    
1188
            definition.addDynFieldBoolean("requiredFields");
1189
            definition.addDynFieldString("internalID");
1190

    
1191
            definition.addDynFieldList("elements")
1192
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1193

    
1194
            definition.addDynFieldObject("tags")
1195
                    .setClassOfValue(Tags.class);
1196
            
1197
        }
1198
    }
1199

    
1200
    @Override
1201
    public FeatureStore getAsFeatureStore() {
1202
        FeatureStore store = FeatureTypeToStoreProviderAdapter.createFeatureStore(this);
1203
        return store;
1204
    }
1205
    
1206
                
1207
    @Override
1208
    public String getNewFieldName() {
1209
        I18nManager i18n = ToolsLocator.getI18nManager();
1210
        String prefix = i18n.getTranslation("_Field");
1211
        String fieldName;
1212
        for (int i = 1; i < 1000; i++) {
1213
            fieldName = prefix+i;
1214
            if( this.get(fieldName)==null ) {
1215
                return fieldName;
1216
            }
1217
        }
1218
        fieldName = prefix + (new Date()).getTime();
1219
        return fieldName;
1220
    }
1221
    
1222
    @Override
1223
   public FeatureType getOriginalFeatureType()  {
1224
        DefaultFeatureStore store = (DefaultFeatureStore) this.getStore();
1225
        if (store==null) {
1226
            return null;
1227
        }
1228
        return store.getOriginalFeatureType(this);
1229
    }
1230
    @Override
1231
    public boolean hasOnlyMetadataChanges(FeatureType old) {
1232
        if( old == null ) {
1233
            throw new NullPointerException();
1234
        }
1235
        // Si hay campos nuevos -> false
1236
        for (FeatureAttributeDescriptor attr : this) {
1237
            if(!attr.isComputed() && old.getAttributeDescriptor(attr.getName())==null) {
1238
                return false;
1239
            }
1240
        }
1241
        
1242
        // Si se ha eliminado algun campo -> false
1243
        for (FeatureAttributeDescriptor attr : old) {
1244
            if(!attr.isComputed() && this.getAttributeDescriptor(attr.getName())==null ) {
1245
                return false;
1246
            }
1247
        }
1248
        
1249
        // No hay campos nuevos ni se ha eliminado ninguno, asi que comparamos
1250
        // los campos uno a uno.
1251
        for (FeatureAttributeDescriptor attr : this) {
1252
            FeatureAttributeDescriptor attrold = old.getAttributeDescriptor(attr.getName());
1253
            if(!attr.isComputed() && !attr.hasOnlyMetadataChanges(attrold) ) {
1254
                return false;
1255
            }
1256
        }
1257
        return true;
1258
    }
1259
    
1260
    public void writeAsDALFile(File file) {
1261
      try {
1262
        DALFile dalFile = DALFile.getDALFile();
1263
        dalFile.setFeatureType(this);
1264
        if( !dalFile.isEmpty() ) {
1265
          dalFile.write(file);
1266
        }
1267
      } catch (Exception ex) {
1268
        throw new RuntimeException("Can't write as DAL file ("+Objects.toString(file)+").", ex);
1269
      }
1270
    }
1271
}