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

History | View | Annotate | Download (37.3 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.lang.ref.WeakReference;
27
import java.util.ArrayList;
28
import java.util.Arrays;
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.Set;
36
import java.util.function.Predicate;
37
import java.util.zip.CRC32;
38
import org.apache.commons.lang3.ArrayUtils;
39
import org.apache.commons.lang3.StringUtils;
40

    
41
import org.cresques.cts.IProjection;
42

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

    
70
public class DefaultFeatureType
71
        extends ArrayList<FeatureAttributeDescriptor>
72
        implements
73
        FeatureType,
74
        Persistent,
75
        DynClass,
76
        DynStruct_v2,
77
        org.gvsig.tools.lang.Cloneable {
78

    
79
    /**
80
     *
81
     */
82
    private static final long serialVersionUID = -7988721447349282215L;
83

    
84
    public static final RecentUsedsAttributesImpl RECENTS_USEDS = new RecentUsedsAttributesImpl();
85

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

    
99
    private List srsList = null;
100
    private WeakReference storeRef;
101
    private boolean requiredFields;
102

    
103
    private String description;
104
    private String label;
105
    private Tags tags;
106

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

    
122
    protected DefaultFeatureType(FeatureStore store, String id) {
123
        this();
124
        if (StringUtils.isEmpty(id)) {
125
            id = "default";
126
        }
127
        this.id = id;
128
        setStore(store);
129
    }
130

    
131
    protected DefaultFeatureType(FeatureStore store) {
132
        this(store, (String) null);
133
    }
134

    
135
    protected DefaultFeatureType(DefaultFeatureType other) {
136
        this(other.getStore(), (String) null);
137
        copyFrom(other, true);
138
    }
139

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

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

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

    
199
    @Override
200
    public String getId() {
201
        return this.id;
202
    }
203

    
204
    @Override
205
    public Object get(String name) {
206
        FeatureAttributeDescriptor attr;
207
        Iterator iter = this.iterator();
208
        while (iter.hasNext()) {
209
            attr = (FeatureAttributeDescriptor) iter.next();
210
            if (attr.getName().equalsIgnoreCase(name)) {
211
                return attr;
212
            }
213
        }
214
        return null;
215
    }
216

    
217
    @Override
218
    public FeatureAttributeDescriptor getAttributeDescriptor(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(int index) {
232
        return (FeatureAttributeDescriptor) super.get(index);
233
    }
234

    
235
    @Override
236
    public FeatureType getCopy() {
237
        return new DefaultFeatureType(this);
238
    }
239

    
240
    @Override
241
    public Object clone() {
242
        return this.getCopy();
243
    }
244

    
245
    public int getDefaultGeometryAttributeIndex() {
246
        return this.defaultGeometryAttributeIndex;
247
    }
248

    
249
    public String getDefaultGeometryAttributeName() {
250
        return this.defaultGeometryAttributeName;
251
    }
252

    
253
    public int getDefaultTimeAttributeIndex() {
254
        return this.defaultTimeAttributeIndex;
255
    }
256

    
257
    public String getDefaultTimeAttributeName() {
258
        return this.defaultTimeAttributeName;
259
    }
260

    
261
    public EditableFeatureType getEditable() {
262
        return new DefaultEditableFeatureType(this);
263
    }
264

    
265
    public int getIndex(String name) {
266
        FeatureAttributeDescriptor attr;
267
        Iterator iter = this.iterator();
268
        while (iter.hasNext()) {
269
            attr = (FeatureAttributeDescriptor) iter.next();
270
            if (attr.getName().equalsIgnoreCase(name)) {
271
                return attr.getIndex();
272
            }
273
        }
274
        return -1;
275
    }
276

    
277
    public FeatureRules getRules() {
278
        return this.rules;
279
    }
280

    
281
    public boolean hasEvaluators() {
282
        return this.hasEvaluators;
283
    }
284

    
285
    public boolean hasEmulators() {
286
        return this.hasEmulators;
287
    }
288

    
289
    public boolean hasRequiredFields() {
290
        return this.requiredFields;
291
    }
292

    
293
    public List getSRSs() {
294
        if (this.srsList == null) {
295
            ArrayList tmp = new ArrayList();
296
            Iterator iter = iterator();
297
            Iterator tmpIter;
298
            boolean allreadyHave;
299
            IProjection tmpSRS;
300
            FeatureAttributeDescriptor attr;
301
            while (iter.hasNext()) {
302
                attr = (FeatureAttributeDescriptor) iter.next();
303
                if (attr.getDataType().getType() == DataTypes.GEOMETRY
304
                        && attr.getSRS() != null) {
305
                    allreadyHave = false;
306
                    tmpIter = tmp.iterator();
307
                    while (tmpIter.hasNext()) {
308
                        tmpSRS = (IProjection) tmpIter.next();
309
                        if (tmpSRS.getAbrev().equals(attr.getSRS().getAbrev())) {
310
                            allreadyHave = true;
311
                            break;
312
                        }
313
                    }
314
                    if (!allreadyHave) {
315
                        tmp.add(attr.getSRS());
316
                    }
317
                }
318
            }
319
            this.srsList = Collections.unmodifiableList(tmp);
320
        }
321
        return this.srsList;
322
    }
323

    
324
    public IProjection getDefaultSRS() {
325
        if (this.getDefaultGeometryAttributeIndex() < 0) {
326
            return null;
327
        }
328
        return this.getAttributeDescriptor(
329
                this.getDefaultGeometryAttributeIndex()).getSRS();
330
    }
331

    
332
    public void validateFeature(Feature feature, int mode) throws DataException {
333
        DefaultFeatureRules rules = (DefaultFeatureRules) this.getRules();
334
        rules.validate(feature, mode);
335
    }
336

    
337
    public FeatureType getSubtype() throws DataException {
338
        return new SubtypeFeatureType(this, null, null, true);
339
    }
340

    
341
    public FeatureType getSubtype(String[] names) throws DataException {
342
        return this.getSubtype(names, null, true);
343
    }
344

    
345
    public FeatureType getSubtype(String[] names, String[] constantsNames) throws DataException {
346
        return this.getSubtype(names, constantsNames, true);
347
    }
348

    
349
    public FeatureType getSubtype(String[] names, String[] constantsNames, boolean includePk) throws DataException {
350
        if (ArrayUtils.isEmpty(names) && ArrayUtils.isEmpty(constantsNames)) {
351
            return (FeatureType) this.clone();
352
        }
353
        return new SubtypeFeatureType(this, names, constantsNames,includePk);
354
    }
355

    
356
    public boolean isSubtypeOf(FeatureType featureType) {
357
        return false;
358
    }
359

    
360
    @Override
361
    public List<FeatureAttributeDescriptor> toList() {
362
        return Collections.unmodifiableList(this);
363
    }
364

    
365
    @Override
366
    public Tags getTags() {
367
        return this.tags;
368
    }
369

    
370
    @Override
371
    public String getLabel() {
372
        return this.label;
373
    }
374

    
375
    @Override
376
    public void setLabel(String label) {
377
        this.label = label;
378
    }
379

    
380
    @Override
381
    public DynField addDynField(String name, int type) {
382
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
383
    }
384

    
385
    class SubtypeFeatureType extends DefaultFeatureType {
386

    
387
        /**
388
         *
389
         */
390
        private static final long serialVersionUID = 6913732960073922540L;
391
        WeakReference parent;
392

    
393
        SubtypeFeatureType(DefaultFeatureType parent, String[] names, String[] constantsNames, boolean includePk)
394
                throws DataException {
395
            super(parent, false);
396
            DefaultFeatureAttributeDescriptor attrcopy;
397
            Set<String> attrnames = new LinkedHashSet<>();
398
            Set<String> requiredAttrnames = new HashSet<>();
399

    
400
            if (ArrayUtils.isEmpty(names)) {
401
                for (FeatureAttributeDescriptor attrdesc : parent) {
402
                    attrnames.add(attrdesc.getName().toLowerCase());
403
                }
404
            } else { 
405
                attrnames.addAll(Arrays.asList(names));
406
                requiredAttrnames.addAll(Arrays.asList(names));
407
            }
408
            // Add required fields for emulated fields
409
            if (parent.hasEmulators) {
410
                // Ojo, este bucle falla cuando hay un campo calculado que depende
411
                // de otro campo calculado.
412
                for (FeatureAttributeDescriptor attrdesc : parent) {
413
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
414
                    if (emulator != null && attrnames.contains(attrdesc.getName().toLowerCase())) {
415
                        String theNames[] = emulator.getRequiredFieldNames();
416
                        if (names != null) {
417
                            for (String name : theNames) {
418
                                name = name.toLowerCase();
419
                                attrnames.add(name);
420
                                requiredAttrnames.add(name);
421
                            }
422
                        }
423
                    }
424
                }
425
            }
426
            // Add missing pk fiels
427
            if (includePk && !parent.hasOID()) {
428
                for (FeatureAttributeDescriptor attrdesc : parent) {
429
                    if (attrdesc.isPrimaryKey()) {
430
                        String name = attrdesc.getName().toLowerCase();
431
                        attrnames.add(name);
432
                        requiredAttrnames.add(name);
433
                    }
434
                }
435
            }
436

    
437
            // Copy attributes
438
            int i = 0;
439
            for (String name : attrnames) {
440
                DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) parent.get(name);
441
                if (attr == null) {
442
                    throw new SubtypeFeatureTypeNameException(name, parent.getId());
443
                }
444
                attrcopy = new DefaultFeatureAttributeDescriptor(attr);
445
                this.add(attrcopy);
446
                attrcopy.index = i++;
447
            }
448

    
449
            // Set the constants attributes.
450
            if (!ArrayUtils.isEmpty(constantsNames)) {
451
                for (String name : constantsNames) {
452
                    if (!requiredAttrnames.contains(name)) {
453
                        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
454
                        attr.setConstantValue(true);
455
                    }
456
                }
457
            }
458

    
459
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
460
            if (this.defaultGeometryAttributeIndex < 0) {
461
                this.defaultGeometryAttributeName = null;
462
            }
463
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
464
            if (this.defaultTimeAttributeIndex < 0) {
465
                this.defaultTimeAttributeName = null;
466
            }
467
            this.parent = new WeakReference(parent);
468
        }
469

    
470
        public FeatureType getSubtype(String[] names, boolean includePk) throws DataException {
471
            return new SubtypeFeatureType((DefaultFeatureType) this.parent
472
                    .get(), names, null, includePk);
473
        }
474

    
475
        public boolean isSubtypeOf(FeatureType featureType) {
476
            if (featureType == null) {
477
                return false;
478
            }
479
            FeatureType parent = (FeatureType) this.parent.get();
480
            return featureType.equals(parent);
481
        }
482

    
483
        public EditableFeatureType getEditable() {
484
            throw new UnsupportedOperationException();
485
        }
486
    }
487

    
488
    public class SubtypeFeatureTypeNameException extends DataException {
489

    
490
        /**
491
         *
492
         */
493
        private static final long serialVersionUID = -4414242486723260101L;
494
        private final static String MESSAGE_FORMAT = "Attribute name '%(name)' not found in type (%(type)).";
495
        private final static String MESSAGE_KEY = "_SubtypeFeatureTypeNameException";
496

    
497
        public SubtypeFeatureTypeNameException(String name, String type) {
498
            super(MESSAGE_FORMAT, MESSAGE_KEY, serialVersionUID);
499
            setValue("name", name);
500
            setValue("type", type);
501
        }
502
    }
503

    
504
    public boolean hasOID() {
505
        return hasOID;
506
    }
507

    
508
    public String toString() {
509
        StringBuffer s = new StringBuffer();
510
        s.append(this.getId());
511
        s.append(":[");
512
        String attName;
513
        for (int i = 0; i < size(); i++) {
514
            attName = ((FeatureAttributeDescriptor) get(i)).getName().toString();
515
            s.append(attName);
516
            if (i < size() - 1) {
517
                s.append(',');
518
            }
519
        }
520
        s.append(']');
521
        return s.toString();
522
    }
523

    
524
    public Iterator<FeatureAttributeDescriptor> iterator() {
525
        return getIterator(super.iterator());
526
    }
527

    
528
    protected Iterator getIterator(Iterator iter) {
529
        return new DelegatedIterator(iter);
530
    }
531

    
532
    protected class DelegatedIterator implements Iterator {
533

    
534
        protected Iterator iterator;
535

    
536
        public DelegatedIterator(Iterator iter) {
537
            this.iterator = iter;
538
        }
539

    
540
        public boolean hasNext() {
541
            return iterator.hasNext();
542
        }
543

    
544
        public Object next() {
545
            return iterator.next();
546
        }
547

    
548
        public void remove() {
549
            throw new UnsupportedOperationException();
550
        }
551

    
552
    }
553

    
554
    public boolean allowAutomaticValues() {
555
        return this.allowAtomaticValues;
556
    }
557

    
558
    public FeatureAttributeDescriptor[] getAttributeDescriptors() {
559
        return (FeatureAttributeDescriptor[]) super
560
                .toArray(new FeatureAttributeDescriptor[super.size()]);
561
    }
562

    
563
    @Override
564
    public boolean hasPrimaryKey() {
565
        if( pk!=null ) {
566
            return pk.length>0;
567
        }
568
        for (FeatureAttributeDescriptor attr : this) {
569
            if( attr.isPrimaryKey() ) {
570
                return true;
571
            }
572
        }
573
        return false;
574
    }
575

    
576
    @Override
577
    public boolean supportReferences() {
578
        return this.hasOID() || this.hasPrimaryKey();
579
    }
580
    
581
    @Override
582
    public FeatureAttributeDescriptor[] getPrimaryKey() {
583
        if (pk == null) {
584
            List pks = new ArrayList();
585
            Iterator iter = super.iterator();
586
            FeatureAttributeDescriptor attr;
587
            while (iter.hasNext()) {
588
                attr = (FeatureAttributeDescriptor) iter.next();
589
                if (attr.isPrimaryKey()) {
590
                    pks.add(attr);
591
                }
592
            }
593
            if (pks.isEmpty()) {
594
                pk = new FeatureAttributeDescriptor[0];
595
            } else {
596
                pk = (FeatureAttributeDescriptor[]) pks.toArray(new FeatureAttributeDescriptor[pks.size()]);
597
            }
598
        }
599
        return pk;
600
    }
601

    
602
    public FeatureAttributeDescriptor getDefaultGeometryAttribute() {
603
        if (this.defaultGeometryAttributeIndex < 0) {
604
            return null;
605
        }
606
        return (FeatureAttributeDescriptor) super
607
                .get(this.defaultGeometryAttributeIndex);
608
    }
609

    
610
    public boolean equals(Object o) {
611
        if (this == o) {
612
            return true;
613
        }
614
        if (!(o instanceof DefaultFeatureType)) {
615
            return false;
616
        }
617
        DefaultFeatureType other = (DefaultFeatureType) o;
618
        if (!this.id.equals(other.id)) {
619
            return false;
620
        }
621
        if (this.size() != other.size()) {
622
            return false;
623
        }
624
        FeatureAttributeDescriptor attr, attrOther;
625
        Iterator iter, iterOther;
626
        iter = this.iterator();
627
        iterOther = other.iterator();
628
        while (iter.hasNext()) {
629
            attr = (FeatureAttributeDescriptor) iter.next();
630
            attrOther = (FeatureAttributeDescriptor) iterOther.next();
631
            if (!attr.equals(attrOther)) {
632
                return false;
633
            }
634
        }
635

    
636
        if (!StringUtils.equals(defaultGeometryAttributeName, other.defaultGeometryAttributeName)) {
637
            return false;
638
        }
639
        if (!StringUtils.equals(defaultTimeAttributeName, other.defaultTimeAttributeName)) {
640
            return false;
641
        }
642
        return true;
643

    
644
    }
645

    
646
    /**
647
     * Start of DynClass interface implementation READONLY
648
     */
649
    public DynField addDynField(String name) {
650
        throw new UnsupportedOperationException();
651
    }
652

    
653
    public DynField getDeclaredDynField(String name) {
654
        return (DynField) getAttributeDescriptor(name);
655
    }
656

    
657
    public DynField[] getDeclaredDynFields() {
658
        return (DynField[]) getAttributeDescriptors();
659
    }
660

    
661
    public String getDescription() {
662
        return this.description;
663
    }
664

    
665
    public DynField getDynField(String name) {
666
        return (DynField) getAttributeDescriptor(name);
667
    }
668

    
669
    public DynField[] getDynFields() {
670
        return (DynField[]) getAttributeDescriptors();
671
    }
672

    
673
    public String getName() {
674
        return this.id + "_" + internalID;
675
    }
676

    
677
    public void removeDynField(String name) {
678
        throw new UnsupportedOperationException();
679

    
680
    }
681

    
682
    public void addDynMethod(DynMethod dynMethod) {
683
        throw new UnsupportedOperationException();
684

    
685
    }
686

    
687
    public void extend(DynClass dynClass) {
688
        throw new UnsupportedOperationException();
689

    
690
    }
691

    
692
    public void extend(String dynClassName) {
693
        throw new UnsupportedOperationException();
694

    
695
    }
696

    
697
    public void extend(String namespace, String dynClassName) {
698
        throw new UnsupportedOperationException();
699

    
700
    }
701

    
702
    public DynMethod getDeclaredDynMethod(String name)
703
            throws DynMethodException {
704
        return null;
705
    }
706

    
707
    public DynMethod[] getDeclaredDynMethods() throws DynMethodException {
708
        return null;
709
    }
710

    
711
    public DynMethod getDynMethod(String name) throws DynMethodException {
712
        return null;
713
    }
714

    
715
    public DynMethod getDynMethod(int code) throws DynMethodException {
716
        return null;
717
    }
718

    
719
    public DynMethod[] getDynMethods() throws DynMethodException {
720
        return null;
721
    }
722

    
723
    public DynClass[] getSuperDynClasses() {
724
        return null;
725
    }
726

    
727
    public boolean isInstance(DynObject dynObject) {
728
        if (dynObject.getDynClass().getName() == getName()) {
729
            return true;
730
        }
731
        return false;
732
    }
733

    
734
    public DynObject newInstance() {
735

    
736
        throw new UnsupportedOperationException();
737
    }
738

    
739
    public void removeDynMethod(String name) {
740
        throw new UnsupportedOperationException();
741

    
742
    }
743

    
744
    public DynField addDynFieldChoice(String name, int type,
745
            Object defaultValue, DynObjectValueItem[] values,
746
            boolean mandatory, boolean persistent) {
747
        throw new UnsupportedOperationException();
748
    }
749

    
750
    public DynField addDynFieldRange(String name, int type,
751
            Object defaultValue, Object min, Object max, boolean mandatory,
752
            boolean persistent) {
753
        throw new UnsupportedOperationException();
754
    }
755

    
756
    public DynField addDynFieldSingle(String name, int type,
757
            Object defaultValue, boolean mandatory, boolean persistent) {
758
        throw new UnsupportedOperationException();
759
    }
760

    
761
    public void validate(DynObject object) throws DynObjectValidateException {
762
        //FIXME: not sure it's the correct code
763
        if (object instanceof Feature) {
764
            Feature fea = (Feature) object;
765
            if (fea.getType().equals(this)) {
766
                return;
767
            }
768
        }
769
        throw new DynObjectValidateException(this.id);
770
    }
771

    
772
    public DynField addDynFieldLong(String name) {
773
        throw new UnsupportedOperationException();
774
    }
775

    
776
    public DynField addDynFieldChoice(String name, int type,
777
            Object defaultValue, DynObjectValueItem[] values) {
778
        throw new UnsupportedOperationException();
779
    }
780

    
781
    public DynField addDynFieldRange(String name, int type,
782
            Object defaultValue, Object min, Object max) {
783
        throw new UnsupportedOperationException();
784
    }
785

    
786
    public DynField addDynFieldSingle(String name, int type, Object defaultValue) {
787
        throw new UnsupportedOperationException();
788
    }
789

    
790
    public DynField addDynFieldString(String name) {
791
        throw new UnsupportedOperationException();
792
    }
793

    
794
    public DynField addDynFieldInt(String name) {
795
        throw new UnsupportedOperationException();
796
    }
797

    
798
    public DynField addDynFieldDouble(String name) {
799
        throw new UnsupportedOperationException();
800
    }
801

    
802
    public DynField addDynFieldFloat(String name) {
803
        throw new UnsupportedOperationException();
804
    }
805

    
806
    public DynField addDynFieldBoolean(String name) {
807
        throw new UnsupportedOperationException();
808
    }
809

    
810
    public DynField addDynFieldList(String name) {
811
        throw new UnsupportedOperationException();
812
    }
813

    
814
    public DynField addDynFieldMap(String name) {
815
        throw new UnsupportedOperationException();
816
    }
817

    
818
    public DynField addDynFieldObject(String name) {
819
        throw new UnsupportedOperationException();
820
    }
821

    
822
    public DynField addDynFieldSet(String name) {
823
        throw new UnsupportedOperationException();
824
    }
825

    
826
    public DynField addDynFieldArray(String name) {
827
        throw new UnsupportedOperationException();
828
    }
829

    
830
    public DynField addDynFieldDate(String name) {
831
        throw new UnsupportedOperationException();
832
    }
833

    
834
    public void extend(DynStruct struct) {
835
        throw new UnsupportedOperationException();
836
    }
837

    
838
    public String getFullName() {
839
        // TODO: usar el DynClassName
840
        return this.id;
841
    }
842

    
843
    public String getNamespace() {
844
        return "DALFeature";
845
    }
846

    
847
    public DynStruct[] getSuperDynStructs() {
848
        return null;
849
    }
850

    
851
    public void setDescription(String description) {
852
        this.description = description;
853
    }
854

    
855
    public void setNamespace(String namespace) {
856
        throw new UnsupportedOperationException();
857
    }
858

    
859
    public DynField addDynFieldFile(String name) {
860
        throw new UnsupportedOperationException();
861
    }
862

    
863
    public DynField addDynFieldFolder(String name) {
864
        throw new UnsupportedOperationException();
865
    }
866

    
867
    public DynField addDynFieldURL(String name) {
868
        throw new UnsupportedOperationException();
869
    }
870

    
871
    public DynField addDynFieldURI(String name) {
872
        throw new UnsupportedOperationException();
873
    }
874

    
875
    public boolean isExtendable(DynStruct dynStruct) {
876
        return false;
877
    }
878

    
879
    public void extend(DynStruct[] structs) {
880
        // TODO Auto-generated method stub
881

    
882
    }
883

    
884
    public void remove(DynStruct superDynStruct) {
885
        // TODO Auto-generated method stub
886

    
887
    }
888

    
889
    public void removeAll(DynStruct[] superDynStruct) {
890
        // TODO Auto-generated method stub
891

    
892
    }
893

    
894
    public FeatureAttributeDescriptor getDefaultTimeAttribute() {
895
        if (this.defaultTimeAttributeIndex < 0) {
896
            return null;
897
        }
898
        return (FeatureAttributeDescriptor) super
899
                .get(this.defaultTimeAttributeIndex);
900
    }
901

    
902
    public void setDefaultTimeAttributeName(String name) {
903
        if (name == null || name.length() == 0) {
904
            this.defaultTimeAttributeIndex = -1;
905
            return;
906
        }
907
        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
908
        if (attr == null) {
909
            throw new IllegalArgumentException("Attribute '" + name + "' not found.");
910
        }
911
        if (attr.getIndex() < 0) {
912
            fixAll();
913
        }
914
        this.defaultTimeAttributeIndex = attr.getIndex();
915
    }
916

    
917
    protected void fixAll() {
918
        int i = 0;
919
        Iterator iter = super.iterator();
920
        DefaultFeatureAttributeDescriptor attr;
921

    
922
        while (iter.hasNext()) {
923
            attr = (DefaultFeatureAttributeDescriptor) iter.next();
924
            if (attr.getOder() < 1) {
925
                attr.setOrder(i * 10);
926
            }
927
            attr.setIndex(i++);
928
            attr.fixAll();
929
            if (attr.getEvaluator() != null) {
930
                this.hasEvaluators = true;
931
            }
932
            if (attr.getFeatureAttributeEmulator() != null) {
933
                this.hasEmulators = true;
934
                String[] x = attr.getFeatureAttributeEmulator().getRequiredFieldNames();
935
                if (!ArrayUtils.isEmpty(x)) {
936
                    this.requiredFields = true;
937
                }
938
            }
939
            switch (attr.getType()) {
940
                case DataTypes.GEOMETRY:
941
                    if (this.defaultGeometryAttributeName == null) {
942
                        this.defaultGeometryAttributeName = attr.getName();
943
                    }
944
                    break;
945
                case DataTypes.INSTANT:
946
                case DataTypes.INTERVAL:
947
                case DataTypes.DATE:
948
                    if (this.defaultTimeAttributeName == null && attr.isTime()) {
949
                        this.defaultTimeAttributeName = attr.getName();
950
                    }
951
                    break;
952
            }
953
        }
954
        if (this.defaultGeometryAttributeName != null) {
955
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
956
        }
957
        if (this.defaultTimeAttributeName != null) {
958
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
959
        }
960
        this.internalID = Long.toHexString(this.getCRC());
961

    
962
    }
963

    
964
    protected long getCRC() {
965
        StringBuffer buffer = new StringBuffer();
966
        for (int i = 0; i < this.size(); i++) {
967
            FeatureAttributeDescriptor x = this.getAttributeDescriptor(i);
968
            buffer.append(x.getName());
969
            buffer.append(x.getDataTypeName());
970
            buffer.append(x.getSize());
971
        }
972
        CRC32 crc = new CRC32();
973
        byte[] data = buffer.toString().getBytes();
974
        crc.update(data);
975
        return crc.getValue();
976
    }
977

    
978
    @Override
979
    public FeatureStore getStore() {
980
        if (this.storeRef == null) {
981
            return null;
982
        }
983
        return (FeatureStore) this.storeRef.get();
984
    }
985

    
986
    public void setStore(FeatureStore store) {
987
        if (store == null) {
988
            this.storeRef = null;
989
        } else {
990
            this.storeRef = new WeakReference(store);
991
        }
992
    }
993

    
994
    @Override
995
    public List<FeatureAttributeDescriptor> getFilteredAttributes(
996
            Predicate<FeatureAttributeDescriptor> filter,
997
            int max
998
    ) {
999
        List<FeatureAttributeDescriptor> attrs = new ArrayList<>();
1000
        for (FeatureAttributeDescriptor attribute : this) {
1001
            if (filter.test(attribute)) {
1002
                attrs.add(attribute);
1003
            }
1004
        }
1005
        return attrs;
1006
    }
1007
    
1008
    @Override
1009
    public List<FeatureAttributeDescriptor> getRecentUseds() {
1010
        return RECENTS_USEDS.getAttributes(this);
1011
    }
1012
    
1013
    @Override
1014
    public void loadFromState(PersistentState state)
1015
            throws PersistenceException {
1016

    
1017
//        FIXME: rules
1018
        hasEvaluators = state.getBoolean("hasEvaluators");
1019
        hasEmulators = state.getBoolean("hasEmulators");
1020
        defaultGeometryAttributeName = state.getString("defaultGeometryAttributeName");
1021
        defaultTimeAttributeName = state.getString("defaultTimeAttributeName");
1022
        defaultGeometryAttributeIndex = state.getInt("defaultGeometryAttributeIndex");
1023
        defaultTimeAttributeIndex = state.getInt("defaultTimeAttributeIndex");
1024
        id = state.getString("id");
1025
        hasOID = state.getBoolean("hasOID");
1026
        allowAtomaticValues = state.getBoolean("allowAtomaticValues");
1027

    
1028
        requiredFields = state.getBoolean("requiredFields");
1029
        internalID = state.getString("internalID");
1030
        tags = (Tags) state.get("tags");
1031
        if( tags == null ) {
1032
            this.tags = new DefaultTags();
1033
        }
1034

    
1035
        List<FeatureAttributeDescriptor> elements = state.getList("elements");
1036
        for (FeatureAttributeDescriptor element : elements) {
1037
            ((DefaultFeatureAttributeDescriptor) element).setFeatureType(this);
1038
            super.add(element);
1039
        }
1040
        this.pk = null;
1041
        this.fixAll();
1042
    }
1043

    
1044
    @Override
1045
    public void saveToState(PersistentState state) throws PersistenceException {
1046

    
1047
//        FIXME: rules
1048
        state.set("hasEvaluators", hasEvaluators);
1049
        state.set("hasEmulators", hasEmulators);
1050
        state.set("defaultGeometryAttributeName", defaultGeometryAttributeName);
1051
        state.set("defaultTimeAttributeName", defaultTimeAttributeName);
1052
        state.set("defaultGeometryAttributeIndex", defaultGeometryAttributeIndex);
1053
        state.set("defaultTimeAttributeIndex", defaultTimeAttributeIndex);
1054
        state.set("id", id);
1055
        state.set("hasOID", hasOID);
1056
        state.set("allowAtomaticValues", allowAtomaticValues);
1057

    
1058
        state.set("requiredFields", requiredFields);
1059
        state.set("internalID", internalID);
1060

    
1061
        List<FeatureAttributeDescriptor> elements = new ArrayList<>();
1062
        elements.addAll(this);
1063
        state.set("elements", elements);
1064
        state.set("tags", tags);
1065

    
1066
    }
1067

    
1068
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1069

    
1070
    public static void registerPersistenceDefinition() {
1071
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1072

    
1073
        if (manager.getDefinition(FEATTYPE_PERSISTENCE_DEFINITION_NAME)
1074
                == null) {
1075
            DynStruct definition = manager.addDefinition(DefaultFeatureType.class,
1076
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME,
1077
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME
1078
                    + " persistent definition",
1079
                    null,
1080
                    null
1081
            );
1082
//            definition.addDynFieldObject("rules");
1083
            definition.addDynFieldBoolean("hasEvaluators");
1084
            definition.addDynFieldBoolean("hasEmulators");
1085
            definition.addDynFieldString("defaultGeometryAttributeName");
1086
            definition.addDynFieldString("defaultTimeAttributeName");
1087
            definition.addDynFieldInt("defaultGeometryAttributeIndex");
1088
            definition.addDynFieldInt("defaultTimeAttributeIndex");
1089
            definition.addDynFieldString("id");
1090
            definition.addDynFieldBoolean("hasOID");
1091
            definition.addDynFieldBoolean("allowAtomaticValues");
1092

    
1093
            definition.addDynFieldBoolean("requiredFields");
1094
            definition.addDynFieldString("internalID");
1095

    
1096
            definition.addDynFieldList("elements")
1097
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1098

    
1099
            definition.addDynFieldObject("tags")
1100
                    .setClassOfValue(Tags.class);
1101
            
1102
        }
1103
    }
1104

    
1105
    @Override
1106
    public FeatureStore getAsFeatureStore() {
1107
        FeatureStore store = FeatureTypeToStoreProviderAdapter.createFeatureStore(this);
1108
        return store;
1109
    }
1110
    
1111
                
1112
    public String getNewFieldName() {
1113
        I18nManager i18n = ToolsLocator.getI18nManager();
1114
        String prefix = i18n.getTranslation("_Field");
1115
        String fieldName;
1116
        for (int i = 1; i < 1000; i++) {
1117
            fieldName = prefix +"-"+i;
1118
            if( this.get(fieldName)==null ) {
1119
                return fieldName;
1120
            }
1121
        }
1122
        fieldName = prefix + "-" + (new Date()).getTime();
1123
        return fieldName;
1124
    }
1125
    
1126
   public FeatureType getOriginalFeatureType()  {
1127
        DefaultFeatureStore store = (DefaultFeatureStore) this.getStore();
1128
        if (store==null) {
1129
            return null;
1130
        }
1131
        return store.getOriginalFeatureType(this);
1132
    }
1133
    @Override
1134
    public boolean hasOnlyMetadataChanges(FeatureType old) {
1135
        if( old == null ) {
1136
            throw new NullPointerException();
1137
        }
1138
        // Si hay campos nuevos -> false
1139
        for (FeatureAttributeDescriptor attr : this) {
1140
            if( old.getAttributeDescriptor(attr.getName())==null ) {
1141
                return false;
1142
            }
1143
        }
1144
        
1145
        // Si se ha eliminado algun campo -> false
1146
        for (FeatureAttributeDescriptor attr : old) {
1147
            if( this.getAttributeDescriptor(attr.getName())==null ) {
1148
                return false;
1149
            }
1150
        }
1151
        
1152
        // No hay campos nuevos ni se ha eliminado ninguno, asi que comparamos
1153
        // los campos uno a uno.
1154
        for (FeatureAttributeDescriptor attr : this) {
1155
            FeatureAttributeDescriptor attrold = old.getAttributeDescriptor(attr.getName());
1156
            if( !attr.hasOnlyMetadataChanges(attrold) ) {
1157
                return false;
1158
            }
1159
        }
1160
        return true;
1161
    }
1162
}