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

History | View | Annotate | Download (39.7 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
        this.extraColumn = other.extraColumn.getCopy();
195
        try {
196
            this.tags = (Tags) other.tags.clone();
197
        } catch (CloneNotSupportedException ex) {
198
            
199
        }
200
    }
201
    
202
    protected DefaultFeatureAttributeDescriptor getCopyAttributeDescriptor(DefaultFeatureAttributeDescriptor src) {
203
        DefaultFeatureAttributeDescriptor copy = new DefaultFeatureAttributeDescriptor(src);
204
        copy.setFeatureType(this);
205
        return copy;
206
    }
207

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
422
    class SubtypeFeatureType extends DefaultFeatureType {
423

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

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

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

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

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

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

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

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

    
523
        public EditableFeatureType getEditable() {
524
            throw new UnsupportedOperationException();
525
        }
526
    }
527

    
528
    public class SubtypeFeatureTypeNameException extends DataException {
529

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

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

    
544
    public boolean hasOID() {
545
        return hasOID;
546
    }
547

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

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

    
570
    protected Iterator getIterator(Iterator iter) {
571
        return new DelegatedIterator(iter);
572
    }
573

    
574
    protected class DelegatedIterator implements Iterator {
575

    
576
        protected Iterator iterator;
577

    
578
        public DelegatedIterator(Iterator iter) {
579
            this.iterator = iter;
580
        }
581

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

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

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

    
597
    }
598

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

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

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

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

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

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

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

    
692
    }
693

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

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

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

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

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

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

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

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

    
736
    }
737

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

    
742
    }
743

    
744
    public void extend(DynClass dynClass) {
745
        throw new UnsupportedOperationException();
746

    
747
    }
748

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

    
753
    }
754

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

    
759
    }
760

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

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

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

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

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

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

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

    
800
    @Override
801
    public DynObject newInstance() {
802

    
803
        throw new UnsupportedOperationException();
804
    }
805

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

    
810
    }
811

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

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

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

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

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

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

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

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

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

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

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

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

    
886
    public DynField addDynFieldBoolean(String name) {
887
        throw new UnsupportedOperationException();
888
    }
889

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
979
    }
980

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

    
985
    }
986

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

    
990
    }
991

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

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

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

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

    
1061
    }
1062

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

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

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

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

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

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

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

    
1143
    @Override
1144
    public void saveToState(PersistentState state) throws PersistenceException {
1145

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

    
1157
        state.set("requiredFields", requiredFields);
1158
        state.set("internalID", internalID);
1159

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

    
1165
    }
1166

    
1167
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1168

    
1169
    public static void registerPersistenceDefinition() {
1170
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1171

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

    
1192
            definition.addDynFieldBoolean("requiredFields");
1193
            definition.addDynFieldString("internalID");
1194

    
1195
            definition.addDynFieldList("elements")
1196
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1197

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

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