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

History | View | Annotate | Download (41.2 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 org.gvsig.fmap.dal.JsonUtils;
27
import java.io.File;
28
import java.lang.ref.WeakReference;
29
import java.util.ArrayList;
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 javax.json.Json;
41
import javax.json.JsonObject;
42
import javax.json.JsonObjectBuilder;
43
import org.apache.commons.lang3.ArrayUtils;
44
import org.apache.commons.lang3.StringUtils;
45

    
46
import org.cresques.cts.IProjection;
47

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

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

    
86
    /**
87
     *
88
     */
89
    private static final long serialVersionUID = -7988721447349282215L;
90

    
91
    public static final RecentUsedsAttributesImpl RECENTS_USEDS = new RecentUsedsAttributesImpl();
92

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

    
106
    private List srsList = null;
107
    private WeakReference storeRef;
108
    private boolean requiredFields;
109

    
110
    private String description;
111
    private String label;
112
    private Tags tags;
113
    private FeatureExtraColumns extraColumns;
114

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
423
    @Override
424
    public Iterable<FeatureAttributeDescriptor> getAllAttributeDescriptors() {
425
        Set<FeatureAttributeDescriptor> all = new HashSet<FeatureAttributeDescriptor>();
426
        for (FeatureAttributeDescriptor attributeDescriptor : this.getAttributeDescriptors()) {
427
            all.add(attributeDescriptor);
428
        }
429
        for (FeatureAttributeDescriptor extraColumn : this.getExtraColumns().getColumns()) {
430
            all.add(extraColumn);
431
        }
432
        return all;
433
    }
434

    
435
    class SubtypeFeatureType extends DefaultFeatureType {
436

    
437
        /**
438
         *
439
         */
440
        private static final long serialVersionUID = 6913732960073922540L;
441
        WeakReference parent;
442

    
443
        SubtypeFeatureType(DefaultFeatureType parent, String[] names, String[] constantsNames, boolean includePk)
444
                throws DataException {
445
            super(parent, false);
446
            DefaultFeatureAttributeDescriptor attrcopy;
447
            Set<String> attrnames = new LinkedHashSet<>();
448
            Set<String> requiredAttrnames = new HashSet<>();
449

    
450
            if (ArrayUtils.isEmpty(names)) {
451
                for (FeatureAttributeDescriptor attrdesc : parent) {
452
                    attrnames.add(attrdesc.getName().toLowerCase());
453
                }
454
            } else { 
455
                for (String name : names) {
456
                  name = name.toLowerCase();
457
                  attrnames.add(name);
458
                  requiredAttrnames.add(name);
459
                }
460
            }
461
            // Add required fields for emulated fields
462
            if (parent.hasEmulators) {
463
                // Ojo, este bucle falla cuando hay un campo calculado que depende
464
                // de otro campo calculado.
465
                for (FeatureAttributeDescriptor attrdesc : parent) {
466
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
467
                    if (emulator != null && attrnames.contains(attrdesc.getName().toLowerCase())) {
468
                        String theNames[] = emulator.getRequiredFieldNames();
469
                        if (names != null) {
470
                            for (String name : theNames) {
471
                                name = name.toLowerCase();
472
                                attrnames.add(name);
473
                                requiredAttrnames.add(name);
474
                            }
475
                        }
476
                    }
477
                }
478
            }
479
            // Add missing pk fiels
480
            if (includePk && !parent.hasOID()) {
481
                for (FeatureAttributeDescriptor attrdesc : parent) {
482
                    if (attrdesc.isPrimaryKey()) {
483
                        String name = attrdesc.getName().toLowerCase();
484
                        attrnames.add(name);
485
                        requiredAttrnames.add(name);
486
                    }
487
                }
488
            }
489

    
490
            // Copy attributes
491
            int i = 0;
492
            for (String name : attrnames) {
493
                DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) parent.get(name);
494
                if (attr == null) {
495
                    throw new SubtypeFeatureTypeNameException(name, parent.getId());
496
                }
497
                attrcopy = new DefaultFeatureAttributeDescriptor(attr);
498
                this.add(attrcopy);
499
                attrcopy.index = i++;
500
            }
501

    
502
            // Set the constants attributes.
503
            if (!ArrayUtils.isEmpty(constantsNames)) {
504
                for (String name : constantsNames) {
505
                    if (!requiredAttrnames.contains(name.toLowerCase())) {
506
                        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
507
                        attr.setConstantValue(true);
508
                    }
509
                }
510
            }
511

    
512
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
513
            if (this.defaultGeometryAttributeIndex < 0) {
514
                this.defaultGeometryAttributeName = null;
515
            }
516
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
517
            if (this.defaultTimeAttributeIndex < 0) {
518
                this.defaultTimeAttributeName = null;
519
            }
520
            this.parent = new WeakReference(parent);
521
        }
522

    
523
        public FeatureType getSubtype(String[] names, boolean includePk) throws DataException {
524
            return new SubtypeFeatureType((DefaultFeatureType) this.parent
525
                    .get(), names, null, includePk);
526
        }
527

    
528
        public boolean isSubtypeOf(FeatureType featureType) {
529
            if (featureType == null) {
530
                return false;
531
            }
532
            FeatureType parent = (FeatureType) this.parent.get();
533
            return featureType.equals(parent);
534
        }
535

    
536
        public EditableFeatureType getEditable() {
537
            throw new UnsupportedOperationException();
538
        }
539
    }
540

    
541
    public class SubtypeFeatureTypeNameException extends DataException {
542

    
543
        /**
544
         *
545
         */
546
        private static final long serialVersionUID = -4414242486723260101L;
547
        private final static String MESSAGE_FORMAT = "Attribute name '%(name)' not found in type (%(type)).";
548
        private final static String MESSAGE_KEY = "_SubtypeFeatureTypeNameException";
549

    
550
        public SubtypeFeatureTypeNameException(String name, String type) {
551
            super(MESSAGE_FORMAT, MESSAGE_KEY, serialVersionUID);
552
            setValue("name", name);
553
            setValue("type", type);
554
        }
555
    }
556

    
557
    public boolean hasOID() {
558
        return hasOID;
559
    }
560

    
561
    @Override
562
    public String toString() {
563
        StringBuffer s = new StringBuffer();
564
        s.append(this.getId());
565
        s.append(":[");
566
        String attName;
567
        for (int i = 0; i < size(); i++) {
568
            attName = ((FeatureAttributeDescriptor) get(i)).getName().toString();
569
            s.append(attName);
570
            if (i < size() - 1) {
571
                s.append(',');
572
            }
573
        }
574
        s.append(']');
575
        return s.toString();
576
    }
577

    
578
    @Override
579
    public Iterator<FeatureAttributeDescriptor> iterator() {
580
        return getIterator(super.iterator());
581
    }
582

    
583
    protected Iterator getIterator(Iterator iter) {
584
        return new DelegatedIterator(iter);
585
    }
586

    
587
    protected class DelegatedIterator implements Iterator {
588

    
589
        protected Iterator iterator;
590

    
591
        public DelegatedIterator(Iterator iter) {
592
            this.iterator = iter;
593
        }
594

    
595
        @Override
596
        public boolean hasNext() {
597
            return iterator.hasNext();
598
        }
599

    
600
        @Override
601
        public Object next() {
602
            return iterator.next();
603
        }
604

    
605
        @Override
606
        public void remove() {
607
            throw new UnsupportedOperationException();
608
        }
609

    
610
    }
611

    
612
    @Override
613
    public boolean allowAutomaticValues() {
614
        return this.allowAtomaticValues;
615
    }
616

    
617
    @Override
618
    public FeatureAttributeDescriptor[] getAttributeDescriptors() {
619
        return (FeatureAttributeDescriptor[]) super
620
                .toArray(new FeatureAttributeDescriptor[super.size()]);
621
    }
622

    
623
    @Override
624
    public boolean hasPrimaryKey() {
625
        if( pk!=null ) {
626
            return pk.length>0;
627
        }
628
        for (FeatureAttributeDescriptor attr : this) {
629
            if( attr.isPrimaryKey() ) {
630
                return true;
631
            }
632
        }
633
        return false;
634
    }
635

    
636
    @Override
637
    public boolean supportReferences() {
638
        return this.hasOID() || this.hasPrimaryKey();
639
    }
640
    
641
    @Override
642
    public FeatureAttributeDescriptor[] getPrimaryKey() {
643
        if (pk == null) {
644
            List pks = new ArrayList();
645
            Iterator iter = super.iterator();
646
            FeatureAttributeDescriptor attr;
647
            while (iter.hasNext()) {
648
                attr = (FeatureAttributeDescriptor) iter.next();
649
                if (attr.isPrimaryKey()) {
650
                    pks.add(attr);
651
                }
652
            }
653
            if (pks.isEmpty()) {
654
                pk = new FeatureAttributeDescriptor[0];
655
            } else {
656
                pk = (FeatureAttributeDescriptor[]) pks.toArray(new FeatureAttributeDescriptor[pks.size()]);
657
            }
658
        }
659
        return pk;
660
    }
661

    
662
    public FeatureAttributeDescriptor getDefaultGeometryAttribute() {
663
        if (this.defaultGeometryAttributeIndex < 0) {
664
            return null;
665
        }
666
        return (FeatureAttributeDescriptor) super
667
                .get(this.defaultGeometryAttributeIndex);
668
    }
669

    
670
    @Override
671
    public boolean equals(Object o) {
672
        if (this == o) {
673
            return true;
674
        }
675
        if (!(o instanceof DefaultFeatureType)) {
676
            return false;
677
        }
678
        DefaultFeatureType other = (DefaultFeatureType) o;
679
        if (!this.id.equals(other.id)) {
680
            return false;
681
        }
682
        if (this.size() != other.size()) {
683
            return false;
684
        }
685
        FeatureAttributeDescriptor attr, attrOther;
686
        Iterator iter, iterOther;
687
        iter = this.iterator();
688
        iterOther = other.iterator();
689
        while (iter.hasNext()) {
690
            attr = (FeatureAttributeDescriptor) iter.next();
691
            attrOther = (FeatureAttributeDescriptor) iterOther.next();
692
            if (!attr.equals(attrOther)) {
693
                return false;
694
            }
695
        }
696

    
697
        if (!StringUtils.equals(defaultGeometryAttributeName, other.defaultGeometryAttributeName)) {
698
            return false;
699
        }
700
        if (!StringUtils.equals(defaultTimeAttributeName, other.defaultTimeAttributeName)) {
701
            return false;
702
        }
703
        return true;
704

    
705
    }
706

    
707
    /**
708
     * Start of DynClass interface implementation READONLY
709
     */
710
    @Override
711
    public DynField addDynField(String name) {
712
        throw new UnsupportedOperationException();
713
    }
714

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

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

    
725
    @Override
726
    public String getDescription() {
727
        return this.description;
728
    }
729

    
730
    @Override
731
    public DynField getDynField(String name) {
732
        return (DynField) getAttributeDescriptor(name);
733
    }
734

    
735
    @Override
736
    public DynField[] getDynFields() {
737
        return (DynField[]) getAttributeDescriptors();
738
    }
739

    
740
    @Override
741
    public String getName() {
742
        return this.id + "_" + internalID;
743
    }
744

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

    
749
    }
750

    
751
    @Override
752
    public void addDynMethod(DynMethod dynMethod) {
753
        throw new UnsupportedOperationException();
754

    
755
    }
756

    
757
    public void extend(DynClass dynClass) {
758
        throw new UnsupportedOperationException();
759

    
760
    }
761

    
762
    @Override
763
    public void extend(String dynClassName) {
764
        throw new UnsupportedOperationException();
765

    
766
    }
767

    
768
    @Override
769
    public void extend(String namespace, String dynClassName) {
770
        throw new UnsupportedOperationException();
771

    
772
    }
773

    
774
    @Override
775
    public DynMethod getDeclaredDynMethod(String name)
776
            throws DynMethodException {
777
        return null;
778
    }
779

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

    
785
    @Override
786
    public DynMethod getDynMethod(String name) throws DynMethodException {
787
        return null;
788
    }
789

    
790
    @Override
791
    public DynMethod getDynMethod(int code) throws DynMethodException {
792
        return null;
793
    }
794

    
795
    @Override
796
    public DynMethod[] getDynMethods() throws DynMethodException {
797
        return null;
798
    }
799

    
800
    @Override
801
    public DynClass[] getSuperDynClasses() {
802
        return null;
803
    }
804

    
805
    @Override
806
    public boolean isInstance(DynObject dynObject) {
807
        if (dynObject.getDynClass().getName() == getName()) {
808
            return true;
809
        }
810
        return false;
811
    }
812

    
813
    @Override
814
    public DynObject newInstance() {
815

    
816
        throw new UnsupportedOperationException();
817
    }
818

    
819
    @Override
820
    public void removeDynMethod(String name) {
821
        throw new UnsupportedOperationException();
822

    
823
    }
824

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

    
832
    @Override
833
    public DynField addDynFieldRange(String name, int type,
834
            Object defaultValue, Object min, Object max, boolean mandatory,
835
            boolean persistent) {
836
        throw new UnsupportedOperationException();
837
    }
838

    
839
    @Override
840
    public DynField addDynFieldSingle(String name, int type,
841
            Object defaultValue, boolean mandatory, boolean persistent) {
842
        throw new UnsupportedOperationException();
843
    }
844

    
845
    @Override
846
    public void validate(DynObject object) throws DynObjectValidateException {
847
        //FIXME: not sure it's the correct code
848
        if (object instanceof Feature) {
849
            Feature fea = (Feature) object;
850
            if (fea.getType().equals(this)) {
851
                return;
852
            }
853
        }
854
        throw new DynObjectValidateException(this.id);
855
    }
856

    
857
    @Override
858
    public DynField addDynFieldLong(String name) {
859
        throw new UnsupportedOperationException();
860
    }
861

    
862
    @Override
863
    public DynField addDynFieldChoice(String name, int type,
864
            Object defaultValue, DynObjectValueItem[] values) {
865
        throw new UnsupportedOperationException();
866
    }
867

    
868
    @Override
869
    public DynField addDynFieldRange(String name, int type,
870
            Object defaultValue, Object min, Object max) {
871
        throw new UnsupportedOperationException();
872
    }
873

    
874
    @Override
875
    public DynField addDynFieldSingle(String name, int type, Object defaultValue) {
876
        throw new UnsupportedOperationException();
877
    }
878

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

    
884
    @Override
885
    public DynField addDynFieldInt(String name) {
886
        throw new UnsupportedOperationException();
887
    }
888

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

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

    
899
    public DynField addDynFieldBoolean(String name) {
900
        throw new UnsupportedOperationException();
901
    }
902

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

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

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

    
918
    @Override
919
    public DynField addDynFieldSet(String name) {
920
        throw new UnsupportedOperationException();
921
    }
922

    
923
    @Override
924
    public DynField addDynFieldArray(String name) {
925
        throw new UnsupportedOperationException();
926
    }
927

    
928
    @Override
929
    public DynField addDynFieldDate(String name) {
930
        throw new UnsupportedOperationException();
931
    }
932

    
933
    @Override
934
    public void extend(DynStruct struct) {
935
        throw new UnsupportedOperationException();
936
    }
937

    
938
    @Override
939
    public String getFullName() {
940
        // TODO: usar el DynClassName
941
        return this.id;
942
    }
943

    
944
    @Override
945
    public String getNamespace() {
946
        return "DALFeature";
947
    }
948

    
949
    @Override
950
    public DynStruct[] getSuperDynStructs() {
951
        return null;
952
    }
953

    
954
    @Override
955
    public void setDescription(String description) {
956
        this.description = description;
957
    }
958

    
959
    @Override
960
    public void setNamespace(String namespace) {
961
        throw new UnsupportedOperationException();
962
    }
963

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

    
969
    @Override
970
    public DynField addDynFieldFolder(String name) {
971
        throw new UnsupportedOperationException();
972
    }
973

    
974
    @Override
975
    public DynField addDynFieldURL(String name) {
976
        throw new UnsupportedOperationException();
977
    }
978

    
979
    @Override
980
    public DynField addDynFieldURI(String name) {
981
        throw new UnsupportedOperationException();
982
    }
983

    
984
    @Override
985
    public boolean isExtendable(DynStruct dynStruct) {
986
        return false;
987
    }
988

    
989
    public void extend(DynStruct[] structs) {
990
        // TODO Auto-generated method stub
991

    
992
    }
993

    
994
    @Override
995
    public void remove(DynStruct superDynStruct) {
996
        // TODO Auto-generated method stub
997

    
998
    }
999

    
1000
    public void removeAll(DynStruct[] superDynStruct) {
1001
        // TODO Auto-generated method stub
1002

    
1003
    }
1004

    
1005
    @Override
1006
    public FeatureAttributeDescriptor getDefaultTimeAttribute() {
1007
        if (this.defaultTimeAttributeIndex < 0) {
1008
            return null;
1009
        }
1010
        return (FeatureAttributeDescriptor) super
1011
                .get(this.defaultTimeAttributeIndex);
1012
    }
1013

    
1014
    public void setDefaultTimeAttributeName(String name) {
1015
        if (name == null || name.length() == 0) {
1016
            this.defaultTimeAttributeIndex = -1;
1017
            return;
1018
        }
1019
        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
1020
        if (attr == null) {
1021
            throw new IllegalArgumentException("Attribute '" + name + "' not found.");
1022
        }
1023
        if (attr.getIndex() < 0) {
1024
            fixAll();
1025
        }
1026
        this.defaultTimeAttributeIndex = attr.getIndex();
1027
    }
1028

    
1029
    protected void fixAll() {
1030
        int i = 0;
1031
        Iterator iter = super.iterator();
1032
        DefaultFeatureAttributeDescriptor attr;
1033

    
1034
        while (iter.hasNext()) {
1035
            attr = (DefaultFeatureAttributeDescriptor) iter.next();
1036
            if (attr.getOder() < 1) {
1037
                attr.setOrder(i * 10);
1038
            }
1039
            attr.setIndex(i++);
1040
            attr.fixAll();
1041
            if (attr.getEvaluator() != null) {
1042
                this.hasEvaluators = true;
1043
            }
1044
            if (attr.getFeatureAttributeEmulator() != null) {
1045
                this.hasEmulators = true;
1046
                String[] x = attr.getFeatureAttributeEmulator().getRequiredFieldNames();
1047
                if (!ArrayUtils.isEmpty(x)) {
1048
                    this.requiredFields = true;
1049
                }
1050
            }
1051
            switch (attr.getType()) {
1052
                case DataTypes.GEOMETRY:
1053
                    if (this.defaultGeometryAttributeName == null
1054
                        || !StringUtils.equals(this.defaultGeometryAttributeName, attr.getName())) {
1055
                        this.defaultGeometryAttributeName = attr.getName();
1056
                    }
1057
                    break;
1058
                case DataTypes.INSTANT:
1059
                case DataTypes.INTERVAL:
1060
                case DataTypes.DATE:
1061
                    if (this.defaultTimeAttributeName == null && attr.isTime()) {
1062
                        this.defaultTimeAttributeName = attr.getName();
1063
                    }
1064
                    break;
1065
            }
1066
        }
1067
        if (this.defaultGeometryAttributeName != null) {
1068
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
1069
        }
1070
        if (this.defaultTimeAttributeName != null) {
1071
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
1072
        }
1073
        this.internalID = Long.toHexString(this.getCRC());
1074

    
1075
    }
1076

    
1077
    protected long getCRC() {
1078
        StringBuffer buffer = new StringBuffer();
1079
        for (int i = 0; i < this.size(); i++) {
1080
            FeatureAttributeDescriptor x = this.getAttributeDescriptor(i);
1081
            buffer.append(x.getName());
1082
            buffer.append(x.getDataTypeName());
1083
            buffer.append(x.getSize());
1084
        }
1085
        CRC32 crc = new CRC32();
1086
        byte[] data = buffer.toString().getBytes();
1087
        crc.update(data);
1088
        return crc.getValue();
1089
    }
1090

    
1091
    @Override
1092
    public FeatureStore getStore() {
1093
        if (this.storeRef == null) {
1094
            return null;
1095
        }
1096
        return (FeatureStore) this.storeRef.get();
1097
    }
1098

    
1099
    public void setStore(FeatureStore store) {
1100
        if (store == null) {
1101
            this.storeRef = null;
1102
        } else {
1103
            this.storeRef = new WeakReference(store);
1104
        }
1105
    }
1106

    
1107
    @Override
1108
    public List<FeatureAttributeDescriptor> getFilteredAttributes(
1109
            Predicate<FeatureAttributeDescriptor> filter,
1110
            int max
1111
    ) {
1112
        List<FeatureAttributeDescriptor> attrs = new ArrayList<>();
1113
        for (FeatureAttributeDescriptor attribute : this) {
1114
            if (filter.test(attribute)) {
1115
                attrs.add(attribute);
1116
            }
1117
        }
1118
        return attrs;
1119
    }
1120
    
1121
    @Override
1122
    public List<FeatureAttributeDescriptor> getRecentUseds() {
1123
        return RECENTS_USEDS.getAttributes(this);
1124
    }
1125
    
1126
    @Override
1127
    public void loadFromState(PersistentState state)
1128
            throws PersistenceException {
1129

    
1130
//        FIXME: rules
1131
        hasEvaluators = state.getBoolean("hasEvaluators");
1132
        hasEmulators = state.getBoolean("hasEmulators");
1133
        defaultGeometryAttributeName = state.getString("defaultGeometryAttributeName");
1134
        defaultTimeAttributeName = state.getString("defaultTimeAttributeName");
1135
        defaultGeometryAttributeIndex = state.getInt("defaultGeometryAttributeIndex");
1136
        defaultTimeAttributeIndex = state.getInt("defaultTimeAttributeIndex");
1137
        id = state.getString("id");
1138
        hasOID = state.getBoolean("hasOID");
1139
        allowAtomaticValues = state.getBoolean("allowAtomaticValues");
1140

    
1141
        requiredFields = state.getBoolean("requiredFields");
1142
        internalID = state.getString("internalID");
1143
        tags = (Tags) state.get("tags");
1144
        if( tags == null ) {
1145
            this.tags = new DefaultTags();
1146
        }
1147

    
1148
        List<FeatureAttributeDescriptor> elements = state.getList("elements");
1149
        for (FeatureAttributeDescriptor element : elements) {
1150
            ((DefaultFeatureAttributeDescriptor) element).setFeatureType(this);
1151
            super.add(element);
1152
        }
1153
        this.pk = null;
1154
        this.fixAll();
1155
    }
1156

    
1157
    @Override
1158
    public void saveToState(PersistentState state) throws PersistenceException {
1159

    
1160
//        FIXME: rules
1161
        state.set("hasEvaluators", hasEvaluators);
1162
        state.set("hasEmulators", hasEmulators);
1163
        state.set("defaultGeometryAttributeName", defaultGeometryAttributeName);
1164
        state.set("defaultTimeAttributeName", defaultTimeAttributeName);
1165
        state.set("defaultGeometryAttributeIndex", defaultGeometryAttributeIndex);
1166
        state.set("defaultTimeAttributeIndex", defaultTimeAttributeIndex);
1167
        state.set("id", id);
1168
        state.set("hasOID", hasOID);
1169
        state.set("allowAtomaticValues", allowAtomaticValues);
1170

    
1171
        state.set("requiredFields", requiredFields);
1172
        state.set("internalID", internalID);
1173

    
1174
        List<FeatureAttributeDescriptor> elements = new ArrayList<>();
1175
        elements.addAll(this);
1176
        state.set("elements", elements);
1177
        state.set("tags", tags);
1178

    
1179
    }
1180

    
1181
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1182

    
1183
    public static void registerPersistenceDefinition() {
1184
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1185

    
1186
        if (manager.getDefinition(FEATTYPE_PERSISTENCE_DEFINITION_NAME)
1187
                == null) {
1188
            DynStruct definition = manager.addDefinition(DefaultFeatureType.class,
1189
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME,
1190
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME
1191
                    + " persistent definition",
1192
                    null,
1193
                    null
1194
            );
1195
//            definition.addDynFieldObject("rules");
1196
            definition.addDynFieldBoolean("hasEvaluators");
1197
            definition.addDynFieldBoolean("hasEmulators");
1198
            definition.addDynFieldString("defaultGeometryAttributeName");
1199
            definition.addDynFieldString("defaultTimeAttributeName");
1200
            definition.addDynFieldInt("defaultGeometryAttributeIndex");
1201
            definition.addDynFieldInt("defaultTimeAttributeIndex");
1202
            definition.addDynFieldString("id");
1203
            definition.addDynFieldBoolean("hasOID");
1204
            definition.addDynFieldBoolean("allowAtomaticValues");
1205

    
1206
            definition.addDynFieldBoolean("requiredFields");
1207
            definition.addDynFieldString("internalID");
1208

    
1209
            definition.addDynFieldList("elements")
1210
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1211

    
1212
            definition.addDynFieldObject("tags")
1213
                    .setClassOfValue(Tags.class);
1214
            
1215
        }
1216
    }
1217

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

    
1295
    @Override
1296
    public JsonObjectBuilder toJsonBuilder() {
1297
        JsonObjectBuilder builder = Json.createObjectBuilder();
1298
        JsonUtils.builder_add(builder, "id",id);
1299
        JsonUtils.builder_add(builder, "internalID",internalID);
1300
        JsonUtils.builder_add(builder, "label",label);
1301
        JsonUtils.builder_add(builder, "description",description);
1302
        JsonUtils.builder_add(builder, "allowAtomaticValues",allowAtomaticValues);
1303
        JsonUtils.builder_add(builder, "hasOID",hasOID);
1304
        JsonUtils.builder_add(builder, "defaultGeometryAttributeName",defaultGeometryAttributeName);
1305
        JsonUtils.builder_add(builder, "defaultTimeAttributeName",defaultTimeAttributeName);        
1306
        JsonUtils.builder_add(builder, "tags", tags);
1307
        JsonUtils.builder_add(builder, "extraColumns", this.extraColumns);
1308
        JsonUtils.builder_add(builder, "descriptors", this);
1309
        
1310
        return builder;        
1311
    }
1312
}