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

History | View | Annotate | Download (43.1 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.fmap.dal.feature.impl;
25

    
26
import java.io.File;
27
import java.lang.ref.WeakReference;
28
import java.util.ArrayList;
29
import java.util.Collections;
30
import java.util.Date;
31
import java.util.HashSet;
32
import java.util.Iterator;
33
import java.util.LinkedHashSet;
34
import java.util.List;
35
import java.util.Objects;
36
import java.util.Set;
37
import java.util.function.Predicate;
38
import java.util.zip.CRC32;
39
import javax.json.JsonObject;
40
import javax.json.JsonValue;
41
import org.apache.commons.lang3.ArrayUtils;
42
import org.apache.commons.lang3.StringUtils;
43

    
44
import org.cresques.cts.IProjection;
45

    
46
import org.gvsig.fmap.dal.DataTypes;
47
import org.gvsig.fmap.dal.exception.DataException;
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.FeatureRules;
53
import org.gvsig.fmap.dal.feature.FeatureStore;
54
import org.gvsig.fmap.dal.feature.FeatureType;
55
import org.gvsig.tools.ToolsLocator;
56
import org.gvsig.tools.dynobject.DynClass;
57
import org.gvsig.tools.dynobject.DynField;
58
import org.gvsig.tools.dynobject.DynMethod;
59
import org.gvsig.tools.dynobject.DynObject;
60
import org.gvsig.tools.dynobject.DynObjectValueItem;
61
import org.gvsig.tools.dynobject.DynStruct;
62
import org.gvsig.tools.dynobject.DynStruct_v2;
63
import org.gvsig.tools.dynobject.Tags;
64
import org.gvsig.tools.dynobject.exception.DynMethodException;
65
import org.gvsig.tools.dynobject.exception.DynObjectValidateException;
66
import org.gvsig.tools.dynobject.impl.DefaultTags;
67
import org.gvsig.tools.i18n.I18nManager;
68
import org.gvsig.tools.persistence.PersistenceManager;
69
import org.gvsig.tools.persistence.Persistent;
70
import org.gvsig.tools.persistence.PersistentState;
71
import org.gvsig.tools.persistence.exception.PersistenceException;
72
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
73
import org.gvsig.fmap.dal.impl.expressionevaluator.DefaultFeatureAttributeEmulatorExpression;
74
import org.gvsig.json.Json;
75
import org.gvsig.json.JsonManager;
76
import org.gvsig.json.JsonObjectBuilder;
77
import org.gvsig.json.SupportToJson;
78

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

    
89
    /**
90
     *
91
     */
92
    private static final long serialVersionUID = -7988721447349282215L;
93

    
94
    public static final RecentUsedsAttributesImpl RECENTS_USEDS = new RecentUsedsAttributesImpl();
95

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

    
109
    private List srsList = null;
110
    private WeakReference storeRef;
111
    private boolean requiredFields;
112

    
113
    private String description;
114
    private String label;
115
    private Tags tags;
116
    private FeatureExtraColumns extraColumns;
117

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

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

    
143
    protected DefaultFeatureType(FeatureStore store) {
144
        this(store, (String) null);
145
    }
146

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

    
152
    protected DefaultFeatureType(DefaultFeatureType other,
153
            boolean copyAttributes) {
154
        this(other.getStore(), (String) null);
155
        this.copyFrom(other, copyAttributes);
156
    }
157

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

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

    
212
    @Override
213
    public String getId() {
214
        return this.id;
215
    }
216

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

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

    
243
    @Override
244
    public FeatureAttributeDescriptor getAttributeDescriptor(int index) {
245
        return (FeatureAttributeDescriptor) super.get(index);
246
    }
247

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

    
257
    @Override
258
    public FeatureType getCopy() {
259
        return new DefaultFeatureType(this);
260
    }
261

    
262
    @Override
263
    public Object clone() {
264
        return this.getCopy();
265
    }
266

    
267
    @Override
268
    public int getDefaultGeometryAttributeIndex() {
269
        return this.defaultGeometryAttributeIndex;
270
    }
271

    
272
    @Override
273
    public String getDefaultGeometryAttributeName() {
274
        return this.defaultGeometryAttributeName;
275
    }
276

    
277
    @Override
278
    public int getDefaultTimeAttributeIndex() {
279
        return this.defaultTimeAttributeIndex;
280
    }
281

    
282
    @Override
283
    public String getDefaultTimeAttributeName() {
284
        return this.defaultTimeAttributeName;
285
    }
286

    
287
    @Override
288
    public EditableFeatureType getEditable() {
289
        return new DefaultEditableFeatureType(this);
290
    }
291

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

    
305
    @Override
306
    public FeatureRules getRules() {
307
        return this.rules;
308
    }
309

    
310
    @Override
311
    public boolean hasEvaluators() {
312
        return this.hasEvaluators;
313
    }
314

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

    
319
    public boolean hasRequiredFields() {
320
        return this.requiredFields;
321
    }
322

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

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

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

    
369
    public FeatureType getSubtype() throws DataException {
370
        return new SubtypeFeatureType(this, null, null, true);
371
    }
372

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

    
377
    public FeatureType getSubtype(String[] names, String[] constantsNames) throws DataException {
378
        return this.getSubtype(names, constantsNames, true);
379
    }
380

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

    
388
    public boolean isSubtypeOf(FeatureType featureType) {
389
        return false;
390
    }
391

    
392
    @Override
393
    public List<FeatureAttributeDescriptor> toList() {
394
        return Collections.unmodifiableList(this);
395
    }
396

    
397
    @Override
398
    public Tags getTags() {
399
        return this.tags;
400
    }
401

    
402
    @Override
403
    public String getLabel() {
404
        return this.label;
405
    }
406

    
407
    @Override
408
    public void setLabel(String label) {
409
        this.label = label;
410
    }
411

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

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

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

    
438
    class SubtypeFeatureType extends DefaultFeatureType {
439

    
440
        /**
441
         *
442
         */
443
        private static final long serialVersionUID = 6913732960073922540L;
444
        WeakReference parent;
445

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

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

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

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

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

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

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

    
539
        public EditableFeatureType getEditable() {
540
            throw new UnsupportedOperationException();
541
        }
542
    }
543

    
544
    public class SubtypeFeatureTypeNameException extends DataException {
545

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

    
553
        public SubtypeFeatureTypeNameException(String name, String type) {
554
            super(MESSAGE_FORMAT, MESSAGE_KEY, serialVersionUID);
555
            setValue("name", name);
556
            setValue("type", type);
557
        }
558
    }
559

    
560
    public boolean hasOID() {
561
        return hasOID;
562
    }
563

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

    
581
    @Override
582
    public Iterator<FeatureAttributeDescriptor> iterator() {
583
        return getIterator(super.iterator());
584
    }
585

    
586
    protected Iterator getIterator(Iterator iter) {
587
        return new DelegatedIterator(iter);
588
    }
589

    
590
    protected class DelegatedIterator implements Iterator {
591

    
592
        protected Iterator iterator;
593

    
594
        public DelegatedIterator(Iterator iter) {
595
            this.iterator = iter;
596
        }
597

    
598
        @Override
599
        public boolean hasNext() {
600
            return iterator.hasNext();
601
        }
602

    
603
        @Override
604
        public Object next() {
605
            return iterator.next();
606
        }
607

    
608
        @Override
609
        public void remove() {
610
            throw new UnsupportedOperationException();
611
        }
612

    
613
    }
614

    
615
    @Override
616
    public boolean allowAutomaticValues() {
617
        return this.allowAtomaticValues;
618
    }
619

    
620
    @Override
621
    public FeatureAttributeDescriptor[] getAttributeDescriptors() {
622
        return (FeatureAttributeDescriptor[]) super
623
                .toArray(new FeatureAttributeDescriptor[super.size()]);
624
    }
625

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

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

    
665
    public FeatureAttributeDescriptor getDefaultGeometryAttribute() {
666
        if (this.defaultGeometryAttributeIndex < 0) {
667
            return null;
668
        }
669
        return (FeatureAttributeDescriptor) super
670
                .get(this.defaultGeometryAttributeIndex);
671
    }
672

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

    
700
        if (!StringUtils.equals(defaultGeometryAttributeName, other.defaultGeometryAttributeName)) {
701
            return false;
702
        }
703
        if (!StringUtils.equals(defaultTimeAttributeName, other.defaultTimeAttributeName)) {
704
            return false;
705
        }
706
        return true;
707

    
708
    }
709

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

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

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

    
728
    @Override
729
    public String getDescription() {
730
        return this.description;
731
    }
732

    
733
    @Override
734
    public DynField getDynField(String name) {
735
        return (DynField) getAttributeDescriptor(name);
736
    }
737

    
738
    @Override
739
    public DynField[] getDynFields() {
740
        return (DynField[]) getAttributeDescriptors();
741
    }
742

    
743
    @Override
744
    public String getName() {
745
        return this.id + "_" + internalID;
746
    }
747

    
748
    @Override
749
    public void removeDynField(String name) {
750
        throw new UnsupportedOperationException();
751

    
752
    }
753

    
754
    @Override
755
    public void addDynMethod(DynMethod dynMethod) {
756
        throw new UnsupportedOperationException();
757

    
758
    }
759

    
760
    public void extend(DynClass dynClass) {
761
        throw new UnsupportedOperationException();
762

    
763
    }
764

    
765
    @Override
766
    public void extend(String dynClassName) {
767
        throw new UnsupportedOperationException();
768

    
769
    }
770

    
771
    @Override
772
    public void extend(String namespace, String dynClassName) {
773
        throw new UnsupportedOperationException();
774

    
775
    }
776

    
777
    @Override
778
    public DynMethod getDeclaredDynMethod(String name)
779
            throws DynMethodException {
780
        return null;
781
    }
782

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

    
788
    @Override
789
    public DynMethod getDynMethod(String name) throws DynMethodException {
790
        return null;
791
    }
792

    
793
    @Override
794
    public DynMethod getDynMethod(int code) throws DynMethodException {
795
        return null;
796
    }
797

    
798
    @Override
799
    public DynMethod[] getDynMethods() throws DynMethodException {
800
        return null;
801
    }
802

    
803
    @Override
804
    public DynClass[] getSuperDynClasses() {
805
        return null;
806
    }
807

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

    
816
    @Override
817
    public DynObject newInstance() {
818

    
819
        throw new UnsupportedOperationException();
820
    }
821

    
822
    @Override
823
    public void removeDynMethod(String name) {
824
        throw new UnsupportedOperationException();
825

    
826
    }
827

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

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

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

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

    
860
    @Override
861
    public DynField addDynFieldLong(String name) {
862
        throw new UnsupportedOperationException();
863
    }
864

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

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

    
877
    @Override
878
    public DynField addDynFieldSingle(String name, int type, Object defaultValue) {
879
        throw new UnsupportedOperationException();
880
    }
881

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

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

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

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

    
902
    public DynField addDynFieldBoolean(String name) {
903
        throw new UnsupportedOperationException();
904
    }
905

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

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

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

    
921
    @Override
922
    public DynField addDynFieldSet(String name) {
923
        throw new UnsupportedOperationException();
924
    }
925

    
926
    @Override
927
    public DynField addDynFieldArray(String name) {
928
        throw new UnsupportedOperationException();
929
    }
930

    
931
    @Override
932
    public DynField addDynFieldDate(String name) {
933
        throw new UnsupportedOperationException();
934
    }
935

    
936
    @Override
937
    public void extend(DynStruct struct) {
938
        throw new UnsupportedOperationException();
939
    }
940

    
941
    @Override
942
    public String getFullName() {
943
        // TODO: usar el DynClassName
944
        return this.id;
945
    }
946

    
947
    @Override
948
    public String getNamespace() {
949
        return "DALFeature";
950
    }
951

    
952
    @Override
953
    public DynStruct[] getSuperDynStructs() {
954
        return null;
955
    }
956

    
957
    @Override
958
    public void setDescription(String description) {
959
        this.description = description;
960
    }
961

    
962
    @Override
963
    public void setNamespace(String namespace) {
964
        throw new UnsupportedOperationException();
965
    }
966

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

    
972
    @Override
973
    public DynField addDynFieldFolder(String name) {
974
        throw new UnsupportedOperationException();
975
    }
976

    
977
    @Override
978
    public DynField addDynFieldURL(String name) {
979
        throw new UnsupportedOperationException();
980
    }
981

    
982
    @Override
983
    public DynField addDynFieldURI(String name) {
984
        throw new UnsupportedOperationException();
985
    }
986

    
987
    @Override
988
    public boolean isExtendable(DynStruct dynStruct) {
989
        return false;
990
    }
991

    
992
    public void extend(DynStruct[] structs) {
993
        // TODO Auto-generated method stub
994

    
995
    }
996

    
997
    @Override
998
    public void remove(DynStruct superDynStruct) {
999
        // TODO Auto-generated method stub
1000

    
1001
    }
1002

    
1003
    public void removeAll(DynStruct[] superDynStruct) {
1004
        // TODO Auto-generated method stub
1005

    
1006
    }
1007

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

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

    
1032
    protected void fixAll() {
1033
        int i = 0;
1034
        Iterator iter = super.iterator();
1035
        DefaultFeatureAttributeDescriptor attr;
1036

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

    
1078
    }
1079

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

    
1094
    @Override
1095
    public FeatureStore getStore() {
1096
        if (this.storeRef == null) {
1097
            return null;
1098
        }
1099
        return (FeatureStore) this.storeRef.get();
1100
    }
1101

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

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

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

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

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

    
1160
    @Override
1161
    public void saveToState(PersistentState state) throws PersistenceException {
1162

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

    
1174
        state.set("requiredFields", requiredFields);
1175
        state.set("internalID", internalID);
1176

    
1177
        List<FeatureAttributeDescriptor> elements = new ArrayList<>();
1178
        elements.addAll(this);
1179
        state.set("elements", elements);
1180
        state.set("tags", tags);
1181

    
1182
    }
1183

    
1184
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1185

    
1186
    public static void registerPersistenceDefinition() {
1187
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1188

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

    
1209
            definition.addDynFieldBoolean("requiredFields");
1210
            definition.addDynFieldString("internalID");
1211

    
1212
            definition.addDynFieldList("elements")
1213
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1214

    
1215
            definition.addDynFieldObject("tags")
1216
                    .setClassOfValue(Tags.class);
1217
            
1218
        }
1219
    }
1220

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

    
1298
    @Override
1299
    public JsonObjectBuilder toJsonBuilder() {
1300
        JsonObjectBuilder builder = Json.createObjectBuilder();
1301
        builder.add_class(this);
1302
        builder.add("id",id);
1303
        builder.add("internalID",internalID);
1304
        builder.add("label",label);
1305
        builder.add("description",description);
1306
        builder.add("allowAtomaticValues",allowAtomaticValues);
1307
        builder.add("hasOID",hasOID);
1308
        builder.add("defaultGeometryAttributeName",defaultGeometryAttributeName);
1309
        builder.add("defaultTimeAttributeName",defaultTimeAttributeName);        
1310
        builder.add("tags", tags);
1311
        builder.add("extraColumns", this.extraColumns);
1312
        builder.add("descriptors", this.iterator());
1313
        
1314
        return builder;        
1315
    }
1316

    
1317
    public void fromJson(JsonObject json) {
1318
        this.clear();
1319
        this.id = json.getString("id", null);
1320
        this.internalID = json.getString("internalID", null);
1321
        this.label = json.getString("label", null);
1322
        this.description = json.getString("description",null);
1323
        this.allowAtomaticValues = json.getBoolean("allowAtomaticValues",false);
1324
        this.hasOID = json.getBoolean("hasOID", false);
1325
        this.defaultGeometryAttributeName = json.getString("defaultGeometryAttributeName", null);
1326
        this.defaultTimeAttributeName = json.getString("defaultTimeAttributeName",null);
1327
        this.tags = (Tags) Json.toObject(json, "tags");
1328
        this.extraColumns = (FeatureExtraColumns) Json.toObject(json, "extraColumns");
1329
        if( json.containsKey("descriptors") ) {
1330
            for (JsonValue jsonValue : json.getJsonArray("descriptors")) {
1331
                DefaultEditableFeatureAttributeDescriptor attr = new DefaultEditableFeatureAttributeDescriptor(this, false);
1332
                attr.fromJson((JsonObject) jsonValue);
1333
                this.add(attr);
1334
            }
1335
        }
1336
    }
1337
    
1338
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
1339
        
1340
        public TheJsonSerializer() {            
1341
        }
1342

    
1343
        @Override
1344
        public Class getObjectClass() {
1345
            return DefaultFeatureType.class;
1346
        }
1347

    
1348
        @Override
1349
        public Object toObject(JsonObject json) {
1350
            DefaultFeatureType o = new DefaultFeatureType();
1351
            o.fromJson(json);
1352
            return o;
1353
        }
1354

    
1355
        @Override
1356
        public JsonObjectBuilder toJsonBuilder(Object value) {
1357
            return ((SupportToJson)value).toJsonBuilder();
1358
        }
1359
        
1360
    }
1361

    
1362
    public static void selfRegister() {
1363
        Json.registerSerializer(new TheJsonSerializer());
1364
    }
1365

    
1366
}