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

History | View | Annotate | Download (45.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.EditableFeature;
49
import org.gvsig.fmap.dal.feature.EditableFeatureType;
50
import org.gvsig.fmap.dal.feature.Feature;
51
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeEmulator;
53
import org.gvsig.fmap.dal.feature.FeatureRules;
54
import org.gvsig.fmap.dal.feature.FeatureStore;
55
import org.gvsig.fmap.dal.feature.FeatureType;
56
import org.gvsig.tools.ToolsLocator;
57
import org.gvsig.tools.dynobject.DynClass;
58
import org.gvsig.tools.dynobject.DynField;
59
import org.gvsig.tools.dynobject.DynMethod;
60
import org.gvsig.tools.dynobject.DynObject;
61
import org.gvsig.tools.dynobject.DynObjectValueItem;
62
import org.gvsig.tools.dynobject.DynStruct;
63
import org.gvsig.tools.dynobject.DynStruct_v2;
64
import org.gvsig.tools.dynobject.Tags;
65
import org.gvsig.tools.dynobject.exception.DynMethodException;
66
import org.gvsig.tools.dynobject.exception.DynObjectValidateException;
67
import org.gvsig.tools.dynobject.impl.DefaultTags;
68
import org.gvsig.tools.i18n.I18nManager;
69
import org.gvsig.tools.persistence.PersistenceManager;
70
import org.gvsig.tools.persistence.Persistent;
71
import org.gvsig.tools.persistence.PersistentState;
72
import org.gvsig.tools.persistence.exception.PersistenceException;
73
import org.gvsig.fmap.dal.feature.FeatureExtraColumns;
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
    protected boolean checkFeaturesAtFinishEditing;
118
    protected boolean checkFeaturesAtInsert;
119

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

    
138
    protected DefaultFeatureType(FeatureStore store, String id) {
139
        this();
140
        if (StringUtils.isEmpty(id)) {
141
            id = "default";
142
        }
143
        this.id = id;
144
        setStore(store);
145
    }
146

    
147
    protected DefaultFeatureType(FeatureStore store) {
148
        this(store, (String) null);
149
    }
150

    
151
    protected DefaultFeatureType(DefaultFeatureType other) {
152
        this(other.getStore(), (String) null);
153
        copyFrom(other, true);
154
    }
155

    
156
    protected DefaultFeatureType(DefaultFeatureType other,
157
            boolean copyAttributes) {
158
        this(other.getStore(), (String) null);
159
        this.copyFrom(other, copyAttributes);
160
    }
161

    
162
    @Override
163
    public void copyFrom(FeatureType other) {
164
        String internalIDSaved = this.internalID;
165
        String idSaved = this.id;
166
        copyFrom((DefaultFeatureType) other, true);
167
        this.id = idSaved;
168
        this.internalID = internalIDSaved;
169
    }
170

    
171
    @Override
172
    public boolean isCheckFeaturesAtFinishEditing() {
173
        return this.checkFeaturesAtFinishEditing;
174
    }
175

    
176
    @Override
177
    public boolean isCheckFeaturesAtInsert() {
178
        return this.checkFeaturesAtInsert;
179
    }
180

    
181

    
182
    protected void addAll(FeatureType attributes) {
183
        for (FeatureAttributeDescriptor attribute : attributes) {
184
            DefaultFeatureAttributeDescriptor copy = this.getCopyAttributeDescriptor((DefaultFeatureAttributeDescriptor) attribute);
185
            super.add(copy);
186
        }
187
        DefaultFeatureType ft = (DefaultFeatureType) attributes; 
188
        this.pk = null;
189
        this.defaultGeometryAttributeName = ft.defaultGeometryAttributeName;
190
        this.defaultTimeAttributeName = ft.defaultTimeAttributeName;
191
        this.defaultGeometryAttributeIndex = ft.defaultGeometryAttributeIndex;
192
        this.defaultTimeAttributeIndex = ft.defaultTimeAttributeIndex;
193
    }
194
    
195
    protected void copyFrom(DefaultFeatureType other, boolean copyAttributes) {
196
        this.id = other.getId();
197
        if (copyAttributes) {
198
            this.addAll((FeatureType)other);
199
        }
200
        this.defaultGeometryAttributeName = other.defaultGeometryAttributeName;
201
        this.defaultTimeAttributeName = other.defaultTimeAttributeName;
202
        this.defaultGeometryAttributeIndex = other.defaultGeometryAttributeIndex;
203
        this.defaultTimeAttributeIndex = other.defaultTimeAttributeIndex;
204

    
205
        this.hasEvaluators = other.hasEvaluators;
206
        this.hasEmulators = other.hasEmulators;
207
        this.rules = (DefaultFeatureRules) other.rules.getCopy();
208
        this.hasOID = other.hasOID;
209
        this.id = other.id; // XXX ???? copiar o no esto????
210
        this.internalID = other.internalID;
211
        this.label = other.label;
212
        this.description = other.description;
213
        this.extraColumns = other.extraColumns.getCopy();
214
        try {
215
            this.tags = (Tags) other.tags.clone();
216
        } catch (CloneNotSupportedException ex) {
217
            
218
        }
219
        this.checkFeaturesAtFinishEditing = other.checkFeaturesAtFinishEditing;
220
        this.checkFeaturesAtInsert = other.checkFeaturesAtInsert;
221
    }
222
    
223
    protected DefaultFeatureAttributeDescriptor getCopyAttributeDescriptor(DefaultFeatureAttributeDescriptor src) {
224
        DefaultFeatureAttributeDescriptor copy = new DefaultFeatureAttributeDescriptor(src);
225
        copy.setFeatureType(this);
226
        return copy;
227
    }
228

    
229
    @Override
230
    public String getId() {
231
        return this.id;
232
    }
233

    
234
    @Override
235
    public Object get(String name) {
236
        FeatureAttributeDescriptor attr;
237
        Iterator iter = this.iterator();
238
        while (iter.hasNext()) {
239
            attr = (FeatureAttributeDescriptor) iter.next();
240
            if (attr.getName().equalsIgnoreCase(name)) {
241
                return attr;
242
            }
243
        }
244
        return null;
245
    }
246

    
247
    @Override
248
    public FeatureAttributeDescriptor getAttributeDescriptor(String name) {
249
        FeatureAttributeDescriptor attr;
250
        Iterator iter = this.iterator();
251
        while (iter.hasNext()) {
252
            attr = (FeatureAttributeDescriptor) iter.next();
253
            if (attr.getName().equalsIgnoreCase(name)) {
254
                return attr;
255
            }
256
        }
257
        return null;
258
    }
259

    
260
    @Override
261
    public FeatureAttributeDescriptor getAttributeDescriptor(int index) {
262
        return (FeatureAttributeDescriptor) super.get(index);
263
    }
264

    
265
    @Override
266
    public String getAttributeName(int index) {
267
      try {
268
        return super.get(index).getName();
269
      } catch(Exception ex) {
270
        return null;
271
      }
272
    }
273

    
274
    @Override
275
    public FeatureType getCopy() {
276
        return new DefaultFeatureType(this);
277
    }
278

    
279
    @Override
280
    public Object clone() {
281
        return this.getCopy();
282
    }
283

    
284
    @Override
285
    public int getDefaultGeometryAttributeIndex() {
286
        return this.defaultGeometryAttributeIndex;
287
    }
288

    
289
    @Override
290
    public String getDefaultGeometryAttributeName() {
291
        return this.defaultGeometryAttributeName;
292
    }
293

    
294
    @Override
295
    public int getDefaultTimeAttributeIndex() {
296
        return this.defaultTimeAttributeIndex;
297
    }
298

    
299
    @Override
300
    public String getDefaultTimeAttributeName() {
301
        return this.defaultTimeAttributeName;
302
    }
303

    
304
    @Override
305
    public EditableFeatureType getEditable() {
306
        return new DefaultEditableFeatureType(this);
307
    }
308

    
309
    @Override
310
    public int getIndex(String name) {
311
        FeatureAttributeDescriptor attr;
312
        Iterator iter = this.iterator();
313
        while (iter.hasNext()) {
314
            attr = (FeatureAttributeDescriptor) iter.next();
315
            if (attr.getName().equalsIgnoreCase(name)) {
316
                return attr.getIndex();
317
            }
318
        }
319
        return -1;
320
    }
321

    
322
    @Override
323
    public FeatureRules getRules() {
324
        return this.rules;
325
    }
326

    
327
    @Override
328
    public boolean hasEvaluators() {
329
        return this.hasEvaluators;
330
    }
331

    
332
    public boolean hasEmulators() {
333
        return this.hasEmulators;
334
    }
335

    
336
    public boolean hasRequiredFields() {
337
        return this.requiredFields;
338
    }
339

    
340
    @Override
341
    public List getSRSs() {
342
        if (this.srsList == null) {
343
            ArrayList tmp = new ArrayList();
344
            Iterator iter = iterator();
345
            Iterator tmpIter;
346
            boolean allreadyHave;
347
            IProjection tmpSRS;
348
            FeatureAttributeDescriptor attr;
349
            while (iter.hasNext()) {
350
                attr = (FeatureAttributeDescriptor) iter.next();
351
                if (attr.getDataType().getType() == DataTypes.GEOMETRY
352
                        && attr.getSRS() != null) {
353
                    allreadyHave = false;
354
                    tmpIter = tmp.iterator();
355
                    while (tmpIter.hasNext()) {
356
                        tmpSRS = (IProjection) tmpIter.next();
357
                        if (tmpSRS.getAbrev().equals(attr.getSRS().getAbrev())) {
358
                            allreadyHave = true;
359
                            break;
360
                        }
361
                    }
362
                    if (!allreadyHave) {
363
                        tmp.add(attr.getSRS());
364
                    }
365
                }
366
            }
367
            this.srsList = Collections.unmodifiableList(tmp);
368
        }
369
        return this.srsList;
370
    }
371

    
372
    @Override
373
    public IProjection getDefaultSRS() {
374
        if (this.getDefaultGeometryAttributeIndex() < 0) {
375
            return null;
376
        }
377
        return this.getAttributeDescriptor(
378
                this.getDefaultGeometryAttributeIndex()).getSRS();
379
    }
380

    
381
    public void validateFeature(EditableFeature feature, int check) throws DataException {
382
        DefaultFeatureRules theRules = (DefaultFeatureRules) this.getRules();
383
        theRules.validate(feature, check);
384
    }
385

    
386
    public void validateFeature(Feature feature, int check) throws DataException {
387
        DefaultFeatureRules theRules = (DefaultFeatureRules) this.getRules();
388
        theRules.validate(feature, check);
389
    }
390

    
391
    public FeatureType getSubtype() throws DataException {
392
        return new SubtypeFeatureType(this, null, null, true);
393
    }
394

    
395
    public FeatureType getSubtype(String[] names) throws DataException {
396
        return this.getSubtype(names, null, true);
397
    }
398

    
399
    public FeatureType getSubtype(String[] names, String[] constantsNames) throws DataException {
400
        return this.getSubtype(names, constantsNames, true);
401
    }
402

    
403
    public FeatureType getSubtype(String[] names, String[] constantsNames, boolean includePk) throws DataException {
404
        if (ArrayUtils.isEmpty(names) && ArrayUtils.isEmpty(constantsNames)) {
405
            return (FeatureType) this.clone();
406
        }
407
        return new SubtypeFeatureType(this, names, constantsNames,includePk);
408
    }
409

    
410
    public boolean isSubtypeOf(FeatureType featureType) {
411
        return false;
412
    }
413

    
414
    @Override
415
    public List<FeatureAttributeDescriptor> toList() {
416
        return Collections.unmodifiableList(this);
417
    }
418

    
419
    @Override
420
    public Tags getTags() {
421
        return this.tags;
422
    }
423

    
424
    @Override
425
    public String getLabel() {
426
        return this.label;
427
    }
428

    
429
    @Override
430
    public void setLabel(String label) {
431
        this.label = label;
432
    }
433

    
434
    @Override
435
    public DynField addDynField(String name, int type) {
436
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
437
    }
438

    
439
    @Override
440
    public FeatureExtraColumns getExtraColumns() {
441
        return extraColumns;
442
    }
443
    
444
    public void setExtraColumn(FeatureExtraColumns extraColumn) { //List<FeatureAttributeDescriptor> descriptors) {
445
          this.extraColumns = extraColumn;
446
    }
447

    
448
    @Override
449
    public Iterable<FeatureAttributeDescriptor> getAllAttributeDescriptors() {
450
        Set<FeatureAttributeDescriptor> all = new HashSet<FeatureAttributeDescriptor>();
451
        for (FeatureAttributeDescriptor attributeDescriptor : this.getAttributeDescriptors()) {
452
            all.add(attributeDescriptor);
453
        }
454
        for (FeatureAttributeDescriptor extraColumn : this.getExtraColumns().getColumns()) {
455
            all.add(extraColumn);
456
        }
457
        return all;
458
    }
459

    
460
    class SubtypeFeatureType extends DefaultFeatureType {
461

    
462
        /**
463
         *
464
         */
465
        private static final long serialVersionUID = 6913732960073922540L;
466
        WeakReference parent;
467

    
468
        SubtypeFeatureType(DefaultFeatureType parent, String[] names, String[] constantsNames, boolean includePk)
469
                throws DataException {
470
            super(parent, false);
471
            DefaultFeatureAttributeDescriptor attrcopy;
472
            Set<String> attrnames = new LinkedHashSet<>();
473
            Set<String> requiredAttrnames = new HashSet<>();
474

    
475
            if (ArrayUtils.isEmpty(names)) {
476
                for (FeatureAttributeDescriptor attrdesc : parent) {
477
                    attrnames.add(attrdesc.getName().toLowerCase());
478
                }
479
            } else { 
480
                for (String name : names) {
481
                  name = name.toLowerCase();
482
                  attrnames.add(name);
483
                  requiredAttrnames.add(name);
484
                }
485
            }
486
            // Add required fields for emulated fields
487
            if (parent.hasEmulators) {
488
                // Ojo, este bucle falla cuando hay un campo calculado que depende
489
                // de otro campo calculado.
490
                for (FeatureAttributeDescriptor attrdesc : parent) {
491
                    FeatureAttributeEmulator emulator = attrdesc.getFeatureAttributeEmulator();
492
                    if (emulator != null && attrnames.contains(attrdesc.getName().toLowerCase())) {
493
                        String theNames[] = emulator.getRequiredFieldNames();
494
                        if (names != null) {
495
                            for (String name : theNames) {
496
                                name = name.toLowerCase();
497
                                attrnames.add(name);
498
                                requiredAttrnames.add(name);
499
                            }
500
                        }
501
                    }
502
                }
503
            }
504
            // Add missing pk fiels
505
            if (includePk && !parent.hasOID()) {
506
                for (FeatureAttributeDescriptor attrdesc : parent) {
507
                    if (attrdesc.isPrimaryKey()) {
508
                        String name = attrdesc.getName().toLowerCase();
509
                        attrnames.add(name);
510
                        requiredAttrnames.add(name);
511
                    }
512
                }
513
            }
514

    
515
            // Copy attributes
516
            int i = 0;
517
            for (String name : attrnames) {
518
                DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) parent.get(name);
519
                if (attr == null) {
520
                    throw new SubtypeFeatureTypeNameException(name, parent.getId());
521
                }
522
                attrcopy = new DefaultFeatureAttributeDescriptor(attr);
523
                this.add(attrcopy);
524
                attrcopy.index = i++;
525
            }
526

    
527
            // Set the constants attributes.
528
            if (!ArrayUtils.isEmpty(constantsNames)) {
529
                for (String name : constantsNames) {
530
                    if (!requiredAttrnames.contains(name.toLowerCase())) {
531
                        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
532
                        attr.setConstantValue(true);
533
                    }
534
                }
535
            }
536

    
537
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
538
            if (this.defaultGeometryAttributeIndex < 0) {
539
                this.defaultGeometryAttributeName = null;
540
            }
541
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
542
            if (this.defaultTimeAttributeIndex < 0) {
543
                this.defaultTimeAttributeName = null;
544
            }
545
            this.parent = new WeakReference(parent);
546
        }
547

    
548
        public FeatureType getSubtype(String[] names, boolean includePk) throws DataException {
549
            return new SubtypeFeatureType((DefaultFeatureType) this.parent
550
                    .get(), names, null, includePk);
551
        }
552

    
553
        public boolean isSubtypeOf(FeatureType featureType) {
554
            if (featureType == null) {
555
                return false;
556
            }
557
            FeatureType parent = (FeatureType) this.parent.get();
558
            return featureType.equals(parent);
559
        }
560

    
561
        public EditableFeatureType getEditable() {
562
            throw new UnsupportedOperationException();
563
        }
564
    }
565

    
566
    public class SubtypeFeatureTypeNameException extends DataException {
567

    
568
        /**
569
         *
570
         */
571
        private static final long serialVersionUID = -4414242486723260101L;
572
        private final static String MESSAGE_FORMAT = "Attribute name '%(name)' not found in type (%(type)).";
573
        private final static String MESSAGE_KEY = "_SubtypeFeatureTypeNameException";
574

    
575
        public SubtypeFeatureTypeNameException(String name, String type) {
576
            super(MESSAGE_FORMAT, MESSAGE_KEY, serialVersionUID);
577
            setValue("name", name);
578
            setValue("type", type);
579
        }
580
    }
581

    
582
    public boolean hasOID() {
583
        return hasOID;
584
    }
585

    
586
    @Override
587
    public String toString() {
588
        StringBuffer s = new StringBuffer();
589
        s.append(this.getId());
590
        s.append(":[");
591
        String attName;
592
        for (int i = 0; i < size(); i++) {
593
            attName = ((FeatureAttributeDescriptor) get(i)).getName().toString();
594
            s.append(attName);
595
            if (i < size() - 1) {
596
                s.append(',');
597
            }
598
        }
599
        s.append(']');
600
        return s.toString();
601
    }
602

    
603
    @Override
604
    public Iterator<FeatureAttributeDescriptor> iterator() {
605
        return getIterator(super.iterator());
606
    }
607

    
608
    protected Iterator getIterator(Iterator iter) {
609
        return new DelegatedIterator(iter);
610
    }
611

    
612
    protected class DelegatedIterator implements Iterator {
613

    
614
        protected Iterator iterator;
615

    
616
        public DelegatedIterator(Iterator iter) {
617
            this.iterator = iter;
618
        }
619

    
620
        @Override
621
        public boolean hasNext() {
622
            return iterator.hasNext();
623
        }
624

    
625
        @Override
626
        public Object next() {
627
            return iterator.next();
628
        }
629

    
630
        @Override
631
        public void remove() {
632
            throw new UnsupportedOperationException();
633
        }
634

    
635
    }
636

    
637
    @Override
638
    public boolean allowAutomaticValues() {
639
        return this.allowAtomaticValues;
640
    }
641

    
642
    @Override
643
    public FeatureAttributeDescriptor[] getAttributeDescriptors() {
644
        return (FeatureAttributeDescriptor[]) super
645
                .toArray(new FeatureAttributeDescriptor[super.size()]);
646
    }
647

    
648
    @Override
649
    public boolean hasPrimaryKey() {
650
        if( pk!=null ) {
651
            return pk.length>0;
652
        }
653
        for (FeatureAttributeDescriptor attr : this) {
654
            if( attr.isPrimaryKey() ) {
655
                return true;
656
            }
657
        }
658
        return false;
659
    }
660

    
661
    @Override
662
    public boolean supportReferences() {
663
        return this.hasOID() || this.hasPrimaryKey();
664
    }
665
    
666
    @Override
667
    public FeatureAttributeDescriptor[] getPrimaryKey() {
668
        if (pk == null) {
669
            List pks = new ArrayList();
670
            Iterator iter = super.iterator();
671
            FeatureAttributeDescriptor attr;
672
            while (iter.hasNext()) {
673
                attr = (FeatureAttributeDescriptor) iter.next();
674
                if (attr.isPrimaryKey()) {
675
                    pks.add(attr);
676
                }
677
            }
678
            if (pks.isEmpty()) {
679
                pk = new FeatureAttributeDescriptor[0];
680
            } else {
681
                pk = (FeatureAttributeDescriptor[]) pks.toArray(new FeatureAttributeDescriptor[pks.size()]);
682
            }
683
        }
684
        return pk;
685
    }
686

    
687
    public FeatureAttributeDescriptor getDefaultGeometryAttribute() {
688
        if (this.defaultGeometryAttributeIndex < 0) {
689
            return null;
690
        }
691
        return (FeatureAttributeDescriptor) super
692
                .get(this.defaultGeometryAttributeIndex);
693
    }
694

    
695
    @Override
696
    public boolean equals(Object o) {
697
        if (this == o) {
698
            return true;
699
        }
700
        if (!(o instanceof DefaultFeatureType)) {
701
            return false;
702
        }
703
        DefaultFeatureType other = (DefaultFeatureType) o;
704
        if (!this.id.equals(other.id)) {
705
            return false;
706
        }
707
        if (this.size() != other.size()) {
708
            return false;
709
        }
710
        FeatureAttributeDescriptor attr, attrOther;
711
        Iterator iter, iterOther;
712
        iter = this.iterator();
713
        iterOther = other.iterator();
714
        while (iter.hasNext()) {
715
            attr = (FeatureAttributeDescriptor) iter.next();
716
            attrOther = (FeatureAttributeDescriptor) iterOther.next();
717
            if (!attr.equals(attrOther)) {
718
                return false;
719
            }
720
        }
721

    
722
        if (!StringUtils.equals(defaultGeometryAttributeName, other.defaultGeometryAttributeName)) {
723
            return false;
724
        }
725
        if (!StringUtils.equals(defaultTimeAttributeName, other.defaultTimeAttributeName)) {
726
            return false;
727
        }
728
        return true;
729

    
730
    }
731

    
732
    /**
733
     * Start of DynClass interface implementation READONLY
734
     */
735
    @Override
736
    public DynField addDynField(String name) {
737
        throw new UnsupportedOperationException();
738
    }
739

    
740
    @Override
741
    public DynField getDeclaredDynField(String name) {
742
        return (DynField) getAttributeDescriptor(name);
743
    }
744

    
745
    @Override
746
    public DynField[] getDeclaredDynFields() {
747
        return (DynField[]) getAttributeDescriptors();
748
    }
749

    
750
    @Override
751
    public String getDescription() {
752
        return this.description;
753
    }
754

    
755
    @Override
756
    public DynField getDynField(String name) {
757
        return (DynField) getAttributeDescriptor(name);
758
    }
759

    
760
    @Override
761
    public DynField[] getDynFields() {
762
        return (DynField[]) getAttributeDescriptors();
763
    }
764

    
765
    @Override
766
    public String getName() {
767
        return this.id + "_" + internalID;
768
    }
769

    
770
    @Override
771
    public void removeDynField(String name) {
772
        throw new UnsupportedOperationException();
773

    
774
    }
775

    
776
    @Override
777
    public void addDynMethod(DynMethod dynMethod) {
778
        throw new UnsupportedOperationException();
779

    
780
    }
781

    
782
    public void extend(DynClass dynClass) {
783
        throw new UnsupportedOperationException();
784

    
785
    }
786

    
787
    @Override
788
    public void extend(String dynClassName) {
789
        throw new UnsupportedOperationException();
790

    
791
    }
792

    
793
    @Override
794
    public void extend(String namespace, String dynClassName) {
795
        throw new UnsupportedOperationException();
796

    
797
    }
798

    
799
    @Override
800
    public DynMethod getDeclaredDynMethod(String name)
801
            throws DynMethodException {
802
        return null;
803
    }
804

    
805
    @Override
806
    public DynMethod[] getDeclaredDynMethods() throws DynMethodException {
807
        return null;
808
    }
809

    
810
    @Override
811
    public DynMethod getDynMethod(String name) throws DynMethodException {
812
        return null;
813
    }
814

    
815
    @Override
816
    public DynMethod getDynMethod(int code) throws DynMethodException {
817
        return null;
818
    }
819

    
820
    @Override
821
    public DynMethod[] getDynMethods() throws DynMethodException {
822
        return null;
823
    }
824

    
825
    @Override
826
    public DynClass[] getSuperDynClasses() {
827
        return null;
828
    }
829

    
830
    @Override
831
    public boolean isInstance(DynObject dynObject) {
832
        if (dynObject.getDynClass().getName() == getName()) {
833
            return true;
834
        }
835
        return false;
836
    }
837

    
838
    @Override
839
    public DynObject newInstance() {
840

    
841
        throw new UnsupportedOperationException();
842
    }
843

    
844
    @Override
845
    public void removeDynMethod(String name) {
846
        throw new UnsupportedOperationException();
847

    
848
    }
849

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

    
857
    @Override
858
    public DynField addDynFieldRange(String name, int type,
859
            Object defaultValue, Object min, Object max, boolean mandatory,
860
            boolean persistent) {
861
        throw new UnsupportedOperationException();
862
    }
863

    
864
    @Override
865
    public DynField addDynFieldSingle(String name, int type,
866
            Object defaultValue, boolean mandatory, boolean persistent) {
867
        throw new UnsupportedOperationException();
868
    }
869

    
870
    @Override
871
    public void validate(DynObject object) throws DynObjectValidateException {
872
        //FIXME: not sure it's the correct code
873
        if (object instanceof Feature) {
874
            Feature fea = (Feature) object;
875
            if (fea.getType().equals(this)) {
876
                return;
877
            }
878
        }
879
        throw new DynObjectValidateException(this.id);
880
    }
881

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

    
887
    @Override
888
    public DynField addDynFieldChoice(String name, int type,
889
            Object defaultValue, DynObjectValueItem[] values) {
890
        throw new UnsupportedOperationException();
891
    }
892

    
893
    @Override
894
    public DynField addDynFieldRange(String name, int type,
895
            Object defaultValue, Object min, Object max) {
896
        throw new UnsupportedOperationException();
897
    }
898

    
899
    @Override
900
    public DynField addDynFieldSingle(String name, int type, Object defaultValue) {
901
        throw new UnsupportedOperationException();
902
    }
903

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

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

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

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

    
924
    public DynField addDynFieldBoolean(String name) {
925
        throw new UnsupportedOperationException();
926
    }
927

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

    
933
    @Override
934
    public DynField addDynFieldMap(String name) {
935
        throw new UnsupportedOperationException();
936
    }
937

    
938
    @Override
939
    public DynField addDynFieldObject(String name) {
940
        throw new UnsupportedOperationException();
941
    }
942

    
943
    @Override
944
    public DynField addDynFieldSet(String name) {
945
        throw new UnsupportedOperationException();
946
    }
947

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

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

    
958
    @Override
959
    public void extend(DynStruct struct) {
960
        throw new UnsupportedOperationException();
961
    }
962

    
963
    @Override
964
    public String getFullName() {
965
        // TODO: usar el DynClassName
966
        return this.id;
967
    }
968

    
969
    @Override
970
    public String getNamespace() {
971
        return "DALFeature";
972
    }
973

    
974
    @Override
975
    public DynStruct[] getSuperDynStructs() {
976
        return null;
977
    }
978

    
979
    @Override
980
    public void setDescription(String description) {
981
        this.description = description;
982
    }
983

    
984
    @Override
985
    public void setNamespace(String namespace) {
986
        throw new UnsupportedOperationException();
987
    }
988

    
989
    @Override
990
    public DynField addDynFieldFile(String name) {
991
        throw new UnsupportedOperationException();
992
    }
993

    
994
    @Override
995
    public DynField addDynFieldFolder(String name) {
996
        throw new UnsupportedOperationException();
997
    }
998

    
999
    @Override
1000
    public DynField addDynFieldURL(String name) {
1001
        throw new UnsupportedOperationException();
1002
    }
1003

    
1004
    @Override
1005
    public DynField addDynFieldURI(String name) {
1006
        throw new UnsupportedOperationException();
1007
    }
1008

    
1009
    @Override
1010
    public boolean isExtendable(DynStruct dynStruct) {
1011
        return false;
1012
    }
1013

    
1014
    public void extend(DynStruct[] structs) {
1015
        // TODO Auto-generated method stub
1016

    
1017
    }
1018

    
1019
    @Override
1020
    public void remove(DynStruct superDynStruct) {
1021
        // TODO Auto-generated method stub
1022

    
1023
    }
1024

    
1025
    public void removeAll(DynStruct[] superDynStruct) {
1026
        // TODO Auto-generated method stub
1027

    
1028
    }
1029

    
1030
    @Override
1031
    public FeatureAttributeDescriptor getDefaultTimeAttribute() {
1032
        if (this.defaultTimeAttributeIndex < 0) {
1033
            return null;
1034
        }
1035
        return (FeatureAttributeDescriptor) super
1036
                .get(this.defaultTimeAttributeIndex);
1037
    }
1038

    
1039
    public void setDefaultTimeAttributeName(String name) {
1040
        if (name == null || name.length() == 0) {
1041
            this.defaultTimeAttributeIndex = -1;
1042
            return;
1043
        }
1044
        DefaultFeatureAttributeDescriptor attr = (DefaultFeatureAttributeDescriptor) this.get(name);
1045
        if (attr == null) {
1046
            throw new IllegalArgumentException("Attribute '" + name + "' not found.");
1047
        }
1048
        if (attr.getIndex() < 0) {
1049
            fixAll();
1050
        }
1051
        this.defaultTimeAttributeIndex = attr.getIndex();
1052
    }
1053

    
1054
    protected void fixAll() {
1055
        int i = 0;
1056
        Iterator iter = super.iterator();
1057
        DefaultFeatureAttributeDescriptor attr;
1058

    
1059
        while (iter.hasNext()) {
1060
            attr = (DefaultFeatureAttributeDescriptor) iter.next();
1061
            if (attr.getOder() < 1) {
1062
                attr.setOrder(i * 10);
1063
            }
1064
            attr.setIndex(i++);
1065
            attr.fixAll();
1066
            if (attr.getEvaluator() != null) {
1067
                this.hasEvaluators = true;
1068
            }
1069
            if (attr.getFeatureAttributeEmulator() != null) {
1070
                this.hasEmulators = true;
1071
                String[] x = attr.getFeatureAttributeEmulator().getRequiredFieldNames();
1072
                if (!ArrayUtils.isEmpty(x)) {
1073
                    this.requiredFields = true;
1074
                }
1075
            }
1076
            switch (attr.getType()) {
1077
                case DataTypes.GEOMETRY:
1078
                    if (this.defaultGeometryAttributeName == null
1079
                        || !StringUtils.equals(this.defaultGeometryAttributeName, attr.getName())) {
1080
                        this.defaultGeometryAttributeName = attr.getName();
1081
                    }
1082
                    break;
1083
                case DataTypes.INSTANT:
1084
                case DataTypes.INTERVAL:
1085
                case DataTypes.DATE:
1086
                    if (this.defaultTimeAttributeName == null && attr.isTime()) {
1087
                        this.defaultTimeAttributeName = attr.getName();
1088
                    }
1089
                    break;
1090
            }
1091
        }
1092
        if (this.defaultGeometryAttributeName != null) {
1093
            this.defaultGeometryAttributeIndex = this.getIndex(this.defaultGeometryAttributeName);
1094
        }
1095
        if (this.defaultTimeAttributeName != null) {
1096
            this.defaultTimeAttributeIndex = this.getIndex(this.defaultTimeAttributeName);
1097
        }
1098
        this.internalID = Long.toHexString(this.getCRC());
1099

    
1100
    }
1101

    
1102
    protected long getCRC() {
1103
        StringBuffer buffer = new StringBuffer();
1104
        for (int i = 0; i < this.size(); i++) {
1105
            FeatureAttributeDescriptor x = this.getAttributeDescriptor(i);
1106
            buffer.append(x.getName());
1107
            buffer.append(x.getDataTypeName());
1108
            buffer.append(x.getSize());
1109
        }
1110
        CRC32 crc = new CRC32();
1111
        byte[] data = buffer.toString().getBytes();
1112
        crc.update(data);
1113
        return crc.getValue();
1114
    }
1115

    
1116
    @Override
1117
    public FeatureStore getStore() {
1118
        if (this.storeRef == null) {
1119
            return null;
1120
        }
1121
        return (FeatureStore) this.storeRef.get();
1122
    }
1123

    
1124
    public void setStore(FeatureStore store) {
1125
        if (store == null) {
1126
            this.storeRef = null;
1127
        } else {
1128
            this.storeRef = new WeakReference(store);
1129
        }
1130
    }
1131

    
1132
    @Override
1133
    public List<FeatureAttributeDescriptor> getFilteredAttributes(
1134
            Predicate<FeatureAttributeDescriptor> filter,
1135
            int max
1136
    ) {
1137
        List<FeatureAttributeDescriptor> attrs = new ArrayList<>();
1138
        for (FeatureAttributeDescriptor attribute : this) {
1139
            if (filter.test(attribute)) {
1140
                attrs.add(attribute);
1141
            }
1142
            if( max>0 && attrs.size()>= max) {
1143
                break;
1144
            }
1145
        }
1146
        return attrs;
1147
    }
1148
    
1149
    @Override
1150
    public List<FeatureAttributeDescriptor> getRecentUseds() {
1151
        return RECENTS_USEDS.getAttributes(this);
1152
    }
1153
    
1154
    @Override
1155
    public void loadFromState(PersistentState state)
1156
            throws PersistenceException {
1157

    
1158
        hasEvaluators = state.getBoolean("hasEvaluators");
1159
        hasEmulators = state.getBoolean("hasEmulators");
1160
        defaultGeometryAttributeName = state.getString("defaultGeometryAttributeName");
1161
        defaultTimeAttributeName = state.getString("defaultTimeAttributeName");
1162
        defaultGeometryAttributeIndex = state.getInt("defaultGeometryAttributeIndex");
1163
        defaultTimeAttributeIndex = state.getInt("defaultTimeAttributeIndex");
1164
        id = state.getString("id");
1165
        hasOID = state.getBoolean("hasOID");
1166
        allowAtomaticValues = state.getBoolean("allowAtomaticValues");
1167

    
1168
        requiredFields = state.getBoolean("requiredFields");
1169
        internalID = state.getString("internalID");
1170
        tags = (Tags) state.get("tags");
1171
        if( tags == null ) {
1172
            this.tags = new DefaultTags();
1173
        }
1174
        this.checkFeaturesAtFinishEditing = state.getBoolean("checkFeaturesAtFinishEditing");
1175
        this.checkFeaturesAtInsert = state.getBoolean("checkFeaturesAtInsert");
1176
        
1177
        List<FeatureAttributeDescriptor> elements = state.getList("elements");
1178
        for (FeatureAttributeDescriptor element : elements) {
1179
            ((DefaultFeatureAttributeDescriptor) element).setFeatureType(this);
1180
            super.add(element);
1181
        }
1182
        this.pk = null;
1183
        
1184
        this.rules = new DefaultFeatureRules();
1185
        List stateRules = state.getList("rules");
1186
        if(stateRules != null) {
1187
            this.rules.addAll(state.getList("rules"));
1188
        }
1189
        this.fixAll();
1190
    }
1191

    
1192
    @Override
1193
    public void saveToState(PersistentState state) throws PersistenceException {
1194

    
1195
//        FIXME: rules
1196
        state.set("hasEvaluators", hasEvaluators);
1197
        state.set("hasEmulators", hasEmulators);
1198
        state.set("defaultGeometryAttributeName", defaultGeometryAttributeName);
1199
        state.set("defaultTimeAttributeName", defaultTimeAttributeName);
1200
        state.set("defaultGeometryAttributeIndex", defaultGeometryAttributeIndex);
1201
        state.set("defaultTimeAttributeIndex", defaultTimeAttributeIndex);
1202
        state.set("id", id);
1203
        state.set("hasOID", hasOID);
1204
        state.set("allowAtomaticValues", allowAtomaticValues);
1205

    
1206
        state.set("requiredFields", requiredFields);
1207
        state.set("internalID", internalID);
1208

    
1209
        List<FeatureAttributeDescriptor> elements = new ArrayList<>();
1210
        elements.addAll(this);
1211
        state.set("elements", elements);
1212
        state.set("tags", tags);
1213
        state.set("checkFeaturesAtFinishEditing",this.checkFeaturesAtFinishEditing);
1214
        state.set("checkFeaturesAtInsert",this.checkFeaturesAtInsert);
1215
        state.set("rules", this.rules.iterator());
1216
    }
1217

    
1218
    private static final String FEATTYPE_PERSISTENCE_DEFINITION_NAME = "FeatureType";
1219

    
1220
    public static void registerPersistenceDefinition() {
1221
        PersistenceManager manager = ToolsLocator.getPersistenceManager();
1222

    
1223
        if (manager.getDefinition(FEATTYPE_PERSISTENCE_DEFINITION_NAME)
1224
                == null) {
1225
            DynStruct definition = manager.addDefinition(DefaultFeatureType.class,
1226
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME,
1227
                    FEATTYPE_PERSISTENCE_DEFINITION_NAME
1228
                    + " persistent definition",
1229
                    null,
1230
                    null
1231
            );
1232
            definition.addDynFieldBoolean("hasEvaluators");
1233
            definition.addDynFieldBoolean("hasEmulators");
1234
            definition.addDynFieldString("defaultGeometryAttributeName");
1235
            definition.addDynFieldString("defaultTimeAttributeName");
1236
            definition.addDynFieldInt("defaultGeometryAttributeIndex");
1237
            definition.addDynFieldInt("defaultTimeAttributeIndex");
1238
            definition.addDynFieldString("id");
1239
            definition.addDynFieldBoolean("hasOID");
1240
            definition.addDynFieldBoolean("allowAtomaticValues");
1241

    
1242
            definition.addDynFieldBoolean("requiredFields");
1243
            definition.addDynFieldString("internalID");
1244

    
1245
            definition.addDynFieldList("elements")
1246
                    .setClassOfItems(FeatureAttributeDescriptor.class);
1247

    
1248
            definition.addDynFieldObject("tags").setClassOfValue(Tags.class);
1249
            definition.addDynFieldBoolean("checkFeaturesAtFinishEditing")
1250
                    .setMandatory(false)
1251
                    .setDefaultFieldValue(true);
1252
            definition.addDynFieldBoolean("checkFeaturesAtInsert")
1253
                    .setMandatory(false)
1254
                    .setDefaultFieldValue(true);
1255
            definition.addDynFieldList("rules")
1256
                    .setClassOfItems(FeatureRules.class);
1257
        }
1258
    }
1259

    
1260
    @Override
1261
    public FeatureStore getAsFeatureStore() {
1262
        FeatureStore store = FeatureTypeToStoreProviderAdapter.createFeatureStore(this);
1263
        return store;
1264
    }
1265
    
1266
                
1267
    @Override
1268
    public String getNewFieldName() {
1269
        I18nManager i18n = ToolsLocator.getI18nManager();
1270
        String prefix = i18n.getTranslation("_Field");
1271
        String fieldName;
1272
        for (int i = 1; i < 1000; i++) {
1273
            fieldName = prefix+i;
1274
            if( this.get(fieldName)==null ) {
1275
                return fieldName;
1276
            }
1277
        }
1278
        fieldName = prefix + (new Date()).getTime();
1279
        return fieldName;
1280
    }
1281
    
1282
    @Override
1283
   public FeatureType getOriginalFeatureType()  {
1284
        DefaultFeatureStore store = (DefaultFeatureStore) this.getStore();
1285
        if (store==null) {
1286
            return null;
1287
        }
1288
        return store.getOriginalFeatureType(this);
1289
    }
1290
    @Override
1291
    public boolean hasOnlyMetadataChanges(FeatureType old) {
1292
        if( old == null ) {
1293
            throw new NullPointerException();
1294
        }
1295
        // Si hay campos nuevos -> false
1296
        for (FeatureAttributeDescriptor attr : this) {
1297
            if(!attr.isComputed() && old.getAttributeDescriptor(attr.getName())==null) {
1298
                return false;
1299
            }
1300
        }
1301
        
1302
        // Si se ha eliminado algun campo -> false
1303
        for (FeatureAttributeDescriptor attr : old) {
1304
            if(!attr.isComputed() && this.getAttributeDescriptor(attr.getName())==null ) {
1305
                return false;
1306
            }
1307
        }
1308
        
1309
        // No hay campos nuevos ni se ha eliminado ninguno, asi que comparamos
1310
        // los campos uno a uno.
1311
        for (FeatureAttributeDescriptor attr : this) {
1312
            FeatureAttributeDescriptor attrold = old.getAttributeDescriptor(attr.getName());
1313
            if(!attr.isComputed() && !attr.hasOnlyMetadataChanges(attrold) ) {
1314
                return false;
1315
            }
1316
        }
1317
        return true;
1318
    }
1319
    
1320
    public void writeAsDALFile(File file) {
1321
      try {
1322
        DALFile dalFile = DALFile.getDALFile();
1323
        dalFile.setFeatureType(this);
1324
        if( !dalFile.isEmpty() ) {
1325
          dalFile.write(file);
1326
        }
1327
      } catch (Exception ex) {
1328
        throw new RuntimeException("Can't write as DAL file ("+Objects.toString(file)+").", ex);
1329
      }
1330
    }
1331
    
1332
    @Override
1333
    public JsonObject toJson() {
1334
        return this.toJsonBuilder().build();
1335
    }
1336

    
1337
    @Override
1338
    public JsonObjectBuilder toJsonBuilder() {
1339
        JsonObjectBuilder builder = Json.createObjectBuilder();
1340
        builder.add_class(this);
1341
        builder.add("id",id);
1342
        builder.add("internalID",internalID);
1343
        builder.add("label",label);
1344
        builder.add("description",description);
1345
        builder.add("allowAtomaticValues",allowAtomaticValues);
1346
        builder.add("hasOID",hasOID);
1347
        builder.add("defaultGeometryAttributeName",defaultGeometryAttributeName);
1348
        builder.add("defaultTimeAttributeName",defaultTimeAttributeName);        
1349
        builder.add("checkFeaturesAtFinishEditing",checkFeaturesAtFinishEditing);        
1350
        builder.add("checkFeaturesAtInsert",checkFeaturesAtInsert);        
1351
        builder.add("tags", tags);
1352
        builder.add("extraColumns", this.extraColumns);
1353
        builder.add("descriptors", this.iterator());
1354
        
1355
        return builder;        
1356
    }
1357

    
1358
    public void fromJson(JsonObject json) {
1359
        this.clear();
1360
        this.id = json.getString("id", null);
1361
        this.internalID = json.getString("internalID", null);
1362
        this.label = json.getString("label", null);
1363
        this.description = json.getString("description",null);
1364
        this.allowAtomaticValues = json.getBoolean("allowAtomaticValues",false);
1365
        this.checkFeaturesAtFinishEditing = json.getBoolean("checkFeaturesAtFinishEditing",true);
1366
        this.checkFeaturesAtInsert = json.getBoolean("checkFeaturesAtInsert",true);
1367
        this.hasOID = json.getBoolean("hasOID", false);
1368
        this.defaultGeometryAttributeName = json.getString("defaultGeometryAttributeName", null);
1369
        this.defaultTimeAttributeName = json.getString("defaultTimeAttributeName",null);
1370
        this.tags = (Tags) Json.toObject(json, "tags");
1371
        this.extraColumns = (FeatureExtraColumns) Json.toObject(json, "extraColumns");
1372
        if( json.containsKey("descriptors") ) {
1373
            for (JsonValue jsonValue : json.getJsonArray("descriptors")) {
1374
                DefaultEditableFeatureAttributeDescriptor attr = new DefaultEditableFeatureAttributeDescriptor(this, false);
1375
                attr.fromJson((JsonObject) jsonValue);
1376
                this.add(attr);
1377
            }
1378
        }
1379
    }
1380
    
1381
    private static class TheJsonSerializer implements JsonManager.JsonSerializer {
1382
        
1383
        public TheJsonSerializer() {            
1384
        }
1385

    
1386
        @Override
1387
        public Class getObjectClass() {
1388
            return DefaultFeatureType.class;
1389
        }
1390

    
1391
        @Override
1392
        public Object toObject(JsonObject json) {
1393
            DefaultFeatureType o = new DefaultFeatureType();
1394
            o.fromJson(json);
1395
            return o;
1396
        }
1397

    
1398
        @Override
1399
        public JsonObjectBuilder toJsonBuilder(Object value) {
1400
            return ((SupportToJson)value).toJsonBuilder();
1401
        }
1402
        
1403
    }
1404

    
1405
    public static void selfRegister() {
1406
        Json.registerSerializer(new TheJsonSerializer());
1407
    }
1408

    
1409
}