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

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

    
42
import org.cresques.cts.IProjection;
43

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

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

    
82
    /**
83
     *
84
     */
85
    private static final long serialVersionUID = -7988721447349282215L;
86

    
87
    public static final RecentUsedsAttributesImpl RECENTS_USEDS = new RecentUsedsAttributesImpl();
88

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

    
102
    private List srsList = null;
103
    private WeakReference storeRef;
104
    private boolean requiredFields;
105

    
106
    private String description;
107
    private String label;
108
    private Tags tags;
109
//    private List<FeatureAttributeDescriptor> descriptors;
110
    private FeatureExtraColumns extraColumn;
111

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

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

    
137
    protected DefaultFeatureType(FeatureStore store) {
138
        this(store, (String) null);
139
    }
140

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
420
    class SubtypeFeatureType extends DefaultFeatureType {
421

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

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

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

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

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

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

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

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

    
521
        public EditableFeatureType getEditable() {
522
            throw new UnsupportedOperationException();
523
        }
524
    }
525

    
526
    public class SubtypeFeatureTypeNameException extends DataException {
527

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

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

    
542
    public boolean hasOID() {
543
        return hasOID;
544
    }
545

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

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

    
568
    protected Iterator getIterator(Iterator iter) {
569
        return new DelegatedIterator(iter);
570
    }
571

    
572
    protected class DelegatedIterator implements Iterator {
573

    
574
        protected Iterator iterator;
575

    
576
        public DelegatedIterator(Iterator iter) {
577
            this.iterator = iter;
578
        }
579

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

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

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

    
595
    }
596

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

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

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

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

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

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

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

    
690
    }
691

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

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

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

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

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

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

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

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

    
734
    }
735

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

    
740
    }
741

    
742
    public void extend(DynClass dynClass) {
743
        throw new UnsupportedOperationException();
744

    
745
    }
746

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

    
751
    }
752

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

    
757
    }
758

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

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

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

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

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

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

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

    
798
    @Override
799
    public DynObject newInstance() {
800

    
801
        throw new UnsupportedOperationException();
802
    }
803

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

    
808
    }
809

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

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

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

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

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

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

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

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

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

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

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

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

    
884
    public DynField addDynFieldBoolean(String name) {
885
        throw new UnsupportedOperationException();
886
    }
887

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
977
    }
978

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

    
983
    }
984

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

    
988
    }
989

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

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

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

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

    
1059
    }
1060

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

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

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

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

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

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

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

    
1141
    @Override
1142
    public void saveToState(PersistentState state) throws PersistenceException {
1143

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

    
1155
        state.set("requiredFields", requiredFields);
1156
        state.set("internalID", internalID);
1157

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

    
1163
    }
1164

    
1165
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1166

    
1167
    public static void registerPersistenceDefinition() {
1168
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1169

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

    
1190
            definition.addDynFieldBoolean("requiredFields");
1191
            definition.addDynFieldString("internalID");
1192

    
1193
            definition.addDynFieldList("elements")
1194
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1195

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

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