Statistics
| Revision:

gvsig-tools / org.gvsig.tools / library / trunk / org.gvsig.tools / org.gvsig.tools.lib / src / main / java / org / gvsig / tools / dynobject / impl / DynClassImportHelper.java @ 1471

History | View | Annotate | Download (39.6 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 modify it under
7
 * the terms of the GNU General Public License as published by the Free Software
8
 * Foundation; either version 2 of the License, or (at your option) any later
9
 * version.
10
 *
11
 * This program is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14
 * details.
15
 *
16
 * You should have received a copy of the GNU General Public License along with
17
 * this program; if not, write to the Free Software Foundation, Inc., 51
18
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
 *
20
 * For any additional information, do not hesitate to contact us at info AT
21
 * gvsig.com, or visit our website www.gvsig.com.
22
 */
23
package org.gvsig.tools.dynobject.impl;
24

    
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.util.ArrayList;
28
import java.util.HashMap;
29
import java.util.Iterator;
30
import java.util.LinkedHashMap;
31
import java.util.List;
32
import java.util.Map;
33
import org.apache.commons.lang3.StringUtils;
34

    
35
import org.gvsig.tools.ToolsLocator;
36
import org.gvsig.tools.dataTypes.CoercionException;
37
import org.gvsig.tools.dataTypes.DataTypes;
38
import org.gvsig.tools.dynobject.DynClass;
39
import org.gvsig.tools.dynobject.DynClassName;
40
import org.gvsig.tools.dynobject.DynClass_v2;
41
import org.gvsig.tools.dynobject.DynField_v2;
42
import org.gvsig.tools.dynobject.DynMethod;
43
import org.gvsig.tools.dynobject.DynObjectManager;
44
import org.gvsig.tools.dynobject.DynObjectRuntimeException;
45
import org.gvsig.tools.dynobject.DynObjectValueItem;
46
import org.gvsig.tools.dynobject.Tags;
47
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
48
import org.gvsig.tools.dynobject.exception.DynMethodException;
49
import org.gvsig.tools.exception.BaseRuntimeException;
50
import org.gvsig.tools.exception.ListBaseException;
51
import org.gvsig.tools.script.Script;
52
import org.slf4j.Logger;
53
import org.slf4j.LoggerFactory;
54
import org.xmlpull.v1.XmlPullParser;
55
import org.xmlpull.v1.XmlPullParserException;
56
import org.xmlpull.v1.XmlPullParserFactory;
57

    
58
public class DynClassImportHelper implements DynClassImportExportTags {
59

    
60
    private static final Logger LOG = LoggerFactory
61
            .getLogger(DynClassImportHelper.class);
62

    
63
    private DynObjectManager manager = ToolsLocator.getDynObjectManager();
64

    
65
    private Map dynClasses = null;
66

    
67
    private Tags globalTags = null;
68
    
69
    private List<Runnable> postLoadActions = new ArrayList<>();
70

    
71
    private class SetCalculateMethodAction implements Runnable {
72

    
73
        private final DynField_v2 field;
74
        private final String methodName;
75

    
76
        public SetCalculateMethodAction(DynField_v2 field, String methodName) {
77
            this.field = field;
78
            this.methodName = methodName;
79
        }
80

    
81
        @Override
82
        public void run() {
83
            DynMethod method = null;
84
            try {
85
                method = manager.getDynMethod(methodName);
86
                field.setCalculateMethod(method);
87
            } catch (DynMethodException ex) {
88
                LOG.warn("Cant create calculate field", ex);
89
            }
90
        }
91

    
92
    }
93
    private class SetDynClassOfItemsAction implements Runnable {
94

    
95
        private final DynField_v2 field;
96
        private final String dynClassName;
97

    
98
        public SetDynClassOfItemsAction(DynField_v2 field, String dynClassName) {
99
            this.field = field;
100
            this.dynClassName = dynClassName;
101
        }
102

    
103
        @Override
104
        public void run() {
105
            DynClass dynStruct = (DynClass) dynClasses.get(dynClassName);
106
            if (dynStruct == null) {
107
                // Try to search in registered DynClasses
108
                field.setClassOfItems(dynClassName);
109
            } else {
110
                field.setClassOfItems(dynStruct);
111
            }
112
        }
113

    
114
    }    
115
    
116
    private class SetDynClassOfValueAction implements Runnable {
117

    
118
        private final DynField_v2 field;
119
        private final String dynClassName;
120

    
121
        public SetDynClassOfValueAction(DynField_v2 field, String dynClassName) {
122
            this.field = field;
123
            this.dynClassName = dynClassName;
124
        }
125

    
126
        @Override
127
        public void run() {
128
            DynClass dynStruct = (DynClass) dynClasses.get(dynClassName);
129
            if (dynStruct == null) {
130
                // Try to search in registered DynClasses
131
                field.setClassOfValue(dynClassName);
132
            } else {
133
                field.setClassOfValue(dynStruct);
134
            }
135
        }
136

    
137
    }
138

    
139
    private String getNullWhenEmptyString(String value) {
140
        if (value != null) {
141
            if (value.trim().length() == 0) {
142
                return null;
143
            }
144
        }
145
        return value;
146

    
147
    }
148

    
149
    private String nextText(XmlPullParser parser)
150
            throws XmlPullParserException, IOException {
151
        return getNullWhenEmptyString(parser.nextText());
152
    }
153

    
154
    private String getAttributeValue(XmlPullParser parser, int i)
155
            throws XmlPullParserException, IOException {
156
        return getNullWhenEmptyString(parser.getAttributeValue(i));
157
    }
158

    
159
    public Map importDefinitions(InputStream resource, ClassLoader loader,
160
            String defaultNamespace) throws XmlPullParserException, IOException {
161

    
162
        XmlPullParserFactory factory = XmlPullParserFactory.newInstance(
163
                ToolsLocator.getInstance().getXmlPullParserFactoryClassNames(),
164
                null);
165

    
166
        XmlPullParser parser = factory.newPullParser();
167

    
168
        parser.setInput(resource, null);
169

    
170
        return importDefinitions(parser, loader, defaultNamespace);
171
    }
172

    
173
    private class Definitions extends HashMap implements Map {
174

    
175
        /**
176
         *
177
         */
178
        private static final long serialVersionUID = -3322643637478345069L;
179

    
180
        public Object put(Object key, Object value) {
181
            return super.put(((String) key).toLowerCase(), value);
182
        }
183

    
184
        public Object get(Object theName) {
185
            DynClass definition;
186
            definition = (DynClass) super.get(((String) theName).toLowerCase());
187
            if (definition != null) {
188
                return definition;
189
            }
190
            // No ha encontrado la clase pedida, podria ser que el namespace
191
            // no coincida, vamos a buscarla ignorando el namespace en caso
192
            // de que este no se haya indicado.
193
            DynClassName name = manager.createDynClassName((String) theName);
194
            if (name.getNamespace() == null) {
195
                // No han especificado namespace, asi que busco la primera
196
                // que tenga como nombre el indicado independientemente del
197
                // namespace que tenga.
198
                Iterator it = this.values().iterator();
199
                while (it.hasNext()) {
200
                    definition = (DynClass) it.next();
201
                    if (definition.getName().equalsIgnoreCase(name.getName())) {
202
                        return definition;
203
                    }
204
                }
205
            } else {
206
                // Han especificaso un namespace, asi que voy a buscar una que
207
                // no tenga namespace y su nombre concuerde.
208
                Iterator it = this.values().iterator();
209
                while (it.hasNext()) {
210
                    definition = (DynClass) it.next();
211
                    if (definition.getNamespace() == null
212
                            && definition.getName().equalsIgnoreCase(
213
                                    name.getName())) {
214
                        return definition;
215
                    }
216
                }
217
            }
218
            return null;
219
        }
220

    
221
        public boolean containsKey(Object key) {
222
            String lowerKey = ((String) key).toLowerCase();
223
            if (super.containsKey(lowerKey)) {
224
                return true;
225
            }
226
            Object value = this.get(lowerKey);
227
            return value != null;
228
        }
229
    }
230

    
231
    public Map importDefinitions(XmlPullParser parser, ClassLoader loader,
232
            String defaultNamespace) throws XmlPullParserException, IOException {
233
        dynClasses = new Definitions();
234
        globalTags = new DefaultTags();
235
        String version = null;
236

    
237
        if (loader == null) {
238
            loader = this.getClass().getClassLoader();
239
        }
240
        parser.nextTag();
241
        parser.require(XmlPullParser.START_TAG, null, DEFINITIONS_TAG);
242
        for (int i = 0; i < parser.getAttributeCount(); i++) {
243
            String name = parser.getAttributeName(i);
244
            if (name.equalsIgnoreCase(VERSION_TAG)) {
245
                version = this.getAttributeValue(parser, i);
246
            } else {
247
                throw new WrongVersionException(parser);
248
            }
249
        }
250
        parser.nextTag();
251
        if (parser.getName().equalsIgnoreCase(VERSION_TAG)) {
252
            parser.require(XmlPullParser.START_TAG, null, VERSION_TAG);
253
            version = parser.nextText();
254
            if (!version.trim().equals(VERSION_VALUE)) {
255
                throw new UnsupportedClassVersionError();
256
            }
257
            parser.require(XmlPullParser.END_TAG, "", VERSION_TAG);
258
            parser.nextTag();
259
        }
260
        if (parser.getName().equalsIgnoreCase(FIELD_TAGS_TAG)) {
261
            parser.nextTag();
262
            while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
263
                    .getName().equals(FIELD_TAGS_TAG))) {
264
                checkEndDocument(parser);
265
                PairValueLabel pair = importValueItem(parser, VALUEITEM_TAGNAME_TAG);
266
                this.globalTags.set(pair.label, pair.value);
267
                parser.nextTag();
268
            }
269
        }
270
        
271
        parser.require(XmlPullParser.START_TAG, "", CLASSES_TAG);
272
        parser.nextTag();
273
        while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
274
                .getName().equals(CLASSES_TAG))) {
275
            checkEndDocument(parser);
276
            DynClass dynClass = importDynClass(parser, loader,
277
                    defaultNamespace, dynClasses);
278
            try {
279
                ((DefaultDynClass) dynClass).check();
280
            } catch (ListBaseException e) {
281
                throw new DynObjectRuntimeException(e);
282
            }
283
            if (dynClasses.get(dynClass.getFullName()) != null) {
284
                throw new DuplicateDynClassException(parser,
285
                        dynClass.getFullName());
286
            }
287
            dynClasses.put(dynClass.getFullName(), dynClass);
288
        }
289
        parser.require(XmlPullParser.END_TAG, "", CLASSES_TAG);
290
        parser.nextTag();
291

    
292
        parser.require(XmlPullParser.END_TAG, "", DEFINITIONS_TAG);
293
        parser.next();
294

    
295
        parser.require(XmlPullParser.END_DOCUMENT, null, null);
296

    
297
        for( Runnable postaction : this.postLoadActions ) {
298
            postaction.run();
299
        }
300
        
301
        LOG.debug("Imported classes {}", new Object[]{getKeys(dynClasses)});
302
        return dynClasses;
303
    }
304

    
305
    private String getKeys(Map theMap) {
306
        List l = new ArrayList(theMap.keySet());
307
        return l.toString();
308
    }
309

    
310
    private DynClass importDynClass(XmlPullParser parser, ClassLoader loader,
311
            String defaultNamespace, Map classes)
312
            throws XmlPullParserException, IOException {
313
        DynObjectManager manager = ToolsLocator.getDynObjectManager();
314
        DynClass_v2 dynClass;
315
        List superClasses = new ArrayList();
316
        Map values = new HashMap();
317
        List tagsValues = null;
318

    
319
        parser.require(XmlPullParser.START_TAG, null, CLASS_TAG);
320
        //
321
        // Collect class attributes from tag attributes
322
        //
323
        for (int i = 0; i < parser.getAttributeCount(); i++) {
324
            values.put(parser.getAttributeName(i),
325
                    this.getAttributeValue(parser, i));
326
        }
327
        parser.nextTag();
328

    
329
        while (!(parser.getEventType() == XmlPullParser.END_TAG && parser.getName().equals(CLASSES_TAG))) {
330
            // Es preciso que exista el tag fields aunque este vacio, si no falla
331
            // el parseo tal como esta implememtado.
332
            checkEndDocument(parser);
333

    
334
            parser.require(XmlPullParser.START_TAG, null, null);
335
            String tagName = parser.getName();
336
            if (tagName.equalsIgnoreCase(CLASS_DESCRIPTION_TAG)) {
337
                values.put(CLASS_DESCRIPTION_TAG, this.nextText(parser));
338

    
339
            } else if (tagName.equalsIgnoreCase(CLASS_NAME_TAG)) {
340
                values.put(CLASS_NAME_TAG, this.nextText(parser));
341

    
342
            } else if (tagName.equalsIgnoreCase(CLASS_LABEL_TAG)) {
343
                values.put(CLASS_LABEL_TAG, this.nextText(parser));
344

    
345
            } else if (tagName.equalsIgnoreCase(CLASS_NAMESPACE_TAG)) {
346
                values.put(CLASS_NAMESPACE_TAG, this.nextText(parser));
347

    
348
            } else if (tagName.equalsIgnoreCase(CLASS_SUPERCLASSNAMES_TAG)) {
349
                parser.nextTag();
350
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
351
                        .getName().equals(CLASS_SUPERCLASSNAMES_TAG))) {
352
                    checkEndDocument(parser);
353
                    parser.require(XmlPullParser.START_TAG, "",
354
                            CLASS_SUPERCLASSNAME_TAG);
355
                    superClasses.add(manager.createDynClassName(
356
                            defaultNamespace, this.nextText(parser)));
357
                    parser.require(XmlPullParser.END_TAG, null,
358
                            CLASS_SUPERCLASSNAME_TAG);
359
                    parser.nextTag();
360
                }
361

    
362
            } else if (tagName.equalsIgnoreCase(CLASS_EXTENDS_TAG)) {
363
                parser.nextTag();
364
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
365
                        .getName().equals(CLASS_EXTENDS_TAG))) {
366
                    checkEndDocument(parser);
367
                    superClasses
368
                            .add(importSuperClass(parser, defaultNamespace));
369
                    parser.nextTag();
370
                }
371

    
372
            } else if (tagName.equalsIgnoreCase(CLASS_TAGS_TAG)) {
373
                parser.nextTag();
374
                tagsValues = new ArrayList();
375
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
376
                        .getName().equals(CLASS_TAGS_TAG))) {
377
                    checkEndDocument(parser);
378
                    tagsValues.add(importValueItem(parser, VALUEITEM_TAGNAME_TAG));
379
                    parser.nextTag();
380
                }
381

    
382
            } else if (tagName.equalsIgnoreCase(CLASS_CODE_TAG)) {
383
                String langcode = parser.getAttributeValue(null, CLASS_LANGCODE_TAG);
384
                if (StringUtils.isEmpty(langcode)) {
385
                    langcode = "python";
386
                }
387
                values.put(CLASS_CODE_TAG, this.nextText(parser));
388
                values.put(CLASS_LANGCODE_TAG, langcode);
389

    
390
            } else {
391
                break;
392
            }
393
            parser.require(XmlPullParser.END_TAG, null, tagName);
394
            parser.nextTag();
395
        }
396
        parser.require(XmlPullParser.START_TAG, null, CLASS_FIELDS_TAG);
397
        parser.nextTag();
398

    
399
        //
400
        // Create dynclass
401
        //
402
        if (values.get(CLASS_NAME_TAG) == null) {
403
            throw new NeedTagOrAttributeException(parser, CLASS_NAME_TAG);
404
        }
405
        if (values.get(CLASS_NAMESPACE_TAG) == null) {
406
            values.put(CLASS_NAMESPACE_TAG, defaultNamespace);
407
        }
408
        dynClass = (DynClass_v2) manager.createDynClass(
409
                (String) values.get(CLASS_NAMESPACE_TAG),
410
                (String) values.get(CLASS_NAME_TAG),
411
                (String) values.get(CLASS_DESCRIPTION_TAG));
412
        dynClass.getTags().add(globalTags);
413
        if (values.get(CLASS_CODE_TAG) != null) {
414
            Script script = ToolsLocator.getScriptManager().createScript(
415
                    dynClass.getName(),
416
                    (String) (values.get(CLASS_CODE_TAG)),
417
                    (String) (values.get(CLASS_LANGCODE_TAG))
418
            );
419
            dynClass.setScript(script);
420
        }
421
        if (values.get(CLASS_LABEL_TAG) != null) {
422
            dynClass.setLabel((String) (values.get(CLASS_LABEL_TAG)));
423
        }
424
        for (int i = 0; i < superClasses.size(); i++) {
425
            DynClassName superClass = (DynClassName) superClasses.get(i);
426
            if (superClass.getName() == null) {
427
                throw new NeedTagOrAttributeException(parser, CLASS_NAME_TAG);
428
            }
429
            DynClass superDynClass = (DynClass) classes.get(superClass
430
                    .getFullName());
431
            if (superDynClass == null) {
432
                superDynClass = ToolsLocator.getDynObjectManager().get(
433
                        superClass.getNamespace(), superClass.getName());
434
                if (superDynClass == null) {
435
                    throw new CantLocateDynClassException(parser,
436
                            superClass.getFullName());
437
                }
438
            }
439
            dynClass.extend(superDynClass);
440
        }
441
        if (tagsValues != null && !tagsValues.isEmpty()) {
442
            if (dynClass instanceof DynClass_v2) {
443
                for (int i = 0; i < tagsValues.size(); i++) {
444
                    PairValueLabel pair = (PairValueLabel) tagsValues.get(i);
445
                    if (pair.label != null) {
446
                        ((DynClass_v2) dynClass).getTags().set(pair.label, pair.value);
447
                    }
448
                }
449
            }
450
        }
451
        //
452
        // Parse and load fields of dynclass
453
        //
454
        while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
455
                .getName().equals(CLASS_FIELDS_TAG))) {
456
            checkEndDocument(parser);
457
            importDynField(parser, (DynClass_v2) dynClass, loader);
458
            parser.nextTag();
459
        }
460
        parser.require(XmlPullParser.END_TAG, null, CLASS_FIELDS_TAG);
461
        parser.nextTag();
462

    
463
        parser.require(XmlPullParser.END_TAG, null, CLASS_TAG);
464
        parser.nextTag();
465
        return dynClass;
466
    }
467

    
468
    private DynClassName importSuperClass(XmlPullParser parser,
469
            String defaultNamespace) throws XmlPullParserException, IOException {
470

    
471
        String name = null;
472
        String namespace = defaultNamespace;
473

    
474
        parser.require(XmlPullParser.START_TAG, null, CLASS_EXTENDS_CLASS_TAG);
475
        for (int i = 0; i < parser.getAttributeCount(); i++) {
476
            String attrname = parser.getAttributeName(i);
477
            if (attrname.equalsIgnoreCase(CLASS_NAME_TAG)) {
478
                name = this.getAttributeValue(parser, i);
479
            } else if (attrname.equalsIgnoreCase(CLASS_NAMESPACE_TAG)) {
480
                namespace = this.getAttributeValue(parser, i);
481
            } else {
482
                throw new UnexpectedTagOrAttributeException(parser, attrname);
483
            }
484
        }
485
        if (name == null) {
486
            name = this.nextText(parser);
487
        } else {
488
            parser.nextTag();
489
        }
490
        parser.require(XmlPullParser.END_TAG, null, CLASS_EXTENDS_CLASS_TAG);
491
        DynClassName dynClassName = manager.createDynClassName(namespace, name);
492
        return dynClassName;
493
    }
494

    
495
    private void importDynField(XmlPullParser parser, DynClass_v2 dynClass,
496
            ClassLoader loader) throws XmlPullParserException, IOException {
497
        DynField_v2 field;
498
        List availableValues = null;
499
        List tagsValues = null;
500
        Map values = new LinkedHashMap();
501

    
502
        parser.require(XmlPullParser.START_TAG, null, FIELD_TAG);
503
        //
504
        // Collect field attributes from tag attributes
505
        //
506
        for (int i = 0; i < parser.getAttributeCount(); i++) {
507
            values.put(parser.getAttributeName(i),
508
                    this.getAttributeValue(parser, i));
509
        }
510
        parser.nextTag();
511

    
512
        //
513
        // Collect field attributes from tags
514
        //
515
        while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
516
                .getName().equals(FIELD_TAG))) {
517
            checkEndDocument(parser);
518

    
519
            parser.require(XmlPullParser.START_TAG, null, null);
520
            String name = parser.getName();
521
            if (name.equalsIgnoreCase(FIELD_NAME_TAG)) {
522
                values.put(FIELD_NAME_TAG, this.nextText(parser));
523

    
524
            } else if (name.equalsIgnoreCase(FIELD_DESCRIPTION_TAG)) {
525
                values.put(FIELD_DESCRIPTION_TAG, this.nextText(parser));
526

    
527
            } else if (name.equalsIgnoreCase(FIELD_TYPE_TAG)) {
528
                values.put(FIELD_TYPE_TAG, this.nextText(parser));
529

    
530
            } else if (name.equalsIgnoreCase(FIELD_SUBTYPE_TAG)) {
531
                values.put(FIELD_SUBTYPE_TAG, this.nextText(parser));
532

    
533
            } else if (name.equalsIgnoreCase(FIELD_GROUP_TAG)) {
534
                values.put(FIELD_GROUP_TAG, this.nextText(parser));
535

    
536
            } else if (name.equalsIgnoreCase(FIELD_LABEL_TAG)) {
537
                values.put(FIELD_LABEL_TAG, this.nextText(parser));
538

    
539
            } else if (name.equalsIgnoreCase(FIELD_ORDER_TAG)) {
540
                values.put(FIELD_ORDER_TAG, this.nextText(parser));
541

    
542
            } else if (name.equalsIgnoreCase(FIELD_ISMANDATORY_TAG)) {
543
                values.put(FIELD_ISMANDATORY_TAG, this.nextText(parser));
544

    
545
            } else if (name.equalsIgnoreCase(FIELD_ISPERSISTENT_TAG)) {
546
                values.put(FIELD_ISPERSISTENT_TAG, this.nextText(parser));
547

    
548
            } else if (name.equalsIgnoreCase(FIELD_MINVALUE_TAG)) {
549
                values.put(FIELD_MINVALUE_TAG, this.nextText(parser));
550

    
551
            } else if (name.equalsIgnoreCase(FIELD_MAXVALUE_TAG)) {
552
                values.put(FIELD_MAXVALUE_TAG, this.nextText(parser));
553

    
554
            } else if (name.equalsIgnoreCase(FIELD_CLASSOFVALUE_TAG)) {
555
                values.put(FIELD_CLASSOFVALUE_TAG, this.nextText(parser));
556

    
557
            } else if (name.equalsIgnoreCase(FIELD_CLASSOFITEMS_TAG)) {
558
                values.put(FIELD_CLASSOFITEMS_TAG, this.nextText(parser));
559

    
560
            } else if (name.equalsIgnoreCase(FIELD_DEFAULTVALUE_TAG)) {
561
                values.put(FIELD_DEFAULTVALUE_TAG, this.nextText(parser));
562

    
563
            } else if (name.equalsIgnoreCase(FIELD_HIDDEN_TAG)) {
564
                values.put(FIELD_HIDDEN_TAG, this.nextText(parser));
565

    
566
            } else if (name.equalsIgnoreCase(FIELD_READONLY_TAG)) {
567
                values.put(FIELD_READONLY_TAG, this.nextText(parser));
568

    
569
            } else if (name.equalsIgnoreCase(FIELD_CALCULATE_TAG)) {
570
                values.put(FIELD_CALCULATE_TAG, this.nextText(parser));
571

    
572
            } else if (name.equalsIgnoreCase(FIELD_AVALILABLEVALUES_TAG)) {
573
                parser.nextTag();
574
                availableValues = new ArrayList();
575
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
576
                        .getName().equals(FIELD_AVALILABLEVALUES_TAG))) {
577
                    checkEndDocument(parser);
578
                    availableValues.add(importValueItem(parser, VALUEITEM_LABEL_TAG));
579
                    parser.nextTag();
580
                }
581

    
582
            } else if (name.equalsIgnoreCase(FIELD_TAGS_TAG)) {
583
                parser.nextTag();
584
                tagsValues = new ArrayList();
585
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
586
                        .getName().equals(FIELD_TAGS_TAG))) {
587
                    checkEndDocument(parser);
588
                    tagsValues.add(importValueItem(parser, VALUEITEM_TAGNAME_TAG));
589
                    parser.nextTag();
590
                }
591

    
592
            } else {
593
                break;
594
            }
595
            parser.require(XmlPullParser.END_TAG, null, name);
596
            parser.nextTag();
597
        }
598
        parser.require(XmlPullParser.END_TAG, null, FIELD_TAG);
599

    
600
        if (values.get(FIELD_NAME_TAG) == null) {
601
            throw new NeedTagOrAttributeException(parser, FIELD_NAME_TAG);
602
        }
603

    
604
        //
605
        // Get type and subtype first
606
        //
607
        String name = FIELD_TYPE_TAG;
608
        String value = (String) values.get(name);
609
        if (value == null) {
610
            throw new InvalidFieldTypeException(parser, value);
611
        }
612
        int type = ToolsLocator.getDataTypesManager().getType(value);
613
        if (type == DataTypes.INVALID) {
614
            throw new InvalidFieldTypeException(parser, value);
615
        }
616
        //
617
        // Create the field
618
        //
619
        field = (DynField_v2) dynClass.addDynField((String) values.get(FIELD_NAME_TAG), type);
620
        field.getTags().add(dynClass.getTags()); 
621

    
622
        //
623
        // Load other values in the field
624
        //
625
        Iterator names = values.keySet().iterator();
626
        while (names.hasNext()) {
627
            name = (String) names.next();
628
            value = (String) values.get(name);
629
            if (value == null) {
630
                continue;
631
            }
632
            if (name.equalsIgnoreCase(FIELD_NAME_TAG)) {
633
                // Do nothing
634

    
635
            } else if (name.equalsIgnoreCase(FIELD_DESCRIPTION_TAG)) {
636
                field.setDescription(value);
637

    
638
            } else if (name.equalsIgnoreCase(FIELD_CALCULATE_TAG)) {
639
                this.postLoadActions.add(new SetCalculateMethodAction(field, value));
640

    
641
            } else if (name.equalsIgnoreCase(FIELD_TYPE_TAG)) {
642
                // Do nothing
643
            } else if (name.equalsIgnoreCase(FIELD_SUBTYPE_TAG)) {
644
                field.setSubtype(value);
645

    
646
            } else if (name.equalsIgnoreCase(FIELD_GROUP_TAG)) {
647
                field.setGroup(value);
648

    
649
            } else if (name.equalsIgnoreCase(FIELD_LABEL_TAG)) {
650
                this.manager.setAttributeValue(field, "label", value);
651

    
652
            } else if (name.equalsIgnoreCase(FIELD_ORDER_TAG)) {
653
                field.setOrder(Integer.parseInt(value));
654

    
655
            } else if (name.equalsIgnoreCase(FIELD_ISMANDATORY_TAG)) {
656
                field.setMandatory(new Boolean(value).booleanValue());
657

    
658
            } else if (name.equalsIgnoreCase(FIELD_ISPERSISTENT_TAG)) {
659
                field.setPersistent(new Boolean(value).booleanValue());
660

    
661
            } else if (name.equalsIgnoreCase(FIELD_HIDDEN_TAG)) {
662
                field.setHidden(new Boolean(value).booleanValue());
663

    
664
            } else if (name.equalsIgnoreCase(FIELD_READONLY_TAG)) {
665
                field.setReadOnly(new Boolean(value).booleanValue());
666

    
667
            } else if (name.equalsIgnoreCase(FIELD_MINVALUE_TAG)) {
668
                field.setMinValue(value);
669

    
670
            } else if (name.equalsIgnoreCase(FIELD_MAXVALUE_TAG)) {
671
                field.setMaxValue(value);
672

    
673
            } else if (name.equalsIgnoreCase(FIELD_DEFAULTVALUE_TAG)) {
674
                field.setDefaultFieldValue(value);
675

    
676
            } else if (name.equalsIgnoreCase(FIELD_TYPEOFITEMS_TAG)) {
677
                int typeOfItems = ToolsLocator.getDataTypesManager().getType(value);
678
                if (typeOfItems == DataTypes.INVALID) {
679
                    throw new InvalidFieldTypeException(parser, value);
680
                }
681
                field.setTypeOfItems(typeOfItems);
682

    
683
            } else if (name.equalsIgnoreCase(FIELD_DYNCLASSOFITEMS_TAG)) {
684
                this.postLoadActions.add(new SetDynClassOfItemsAction(field, value));
685

    
686
            } else if (name.equalsIgnoreCase(FIELD_CLASSOFITEMS_TAG)) {
687
                if (field.getTypeOfItems() == DataTypes.DYNOBJECT) {
688
                    this.postLoadActions.add(new SetDynClassOfItemsAction(field, value));
689
                } else {
690
                    try {
691
                        Class klass;
692
                        klass = Class.forName(value, true, loader);
693
                        field.setClassOfItems(klass);
694
                    } catch (DynFieldIsNotAContainerException e) {
695
                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
696
                        throw new IncompatibleAttributeValueException(parser,
697
                                FIELD_NAME_TAG);
698
                    } catch (ClassNotFoundException e) {
699
                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
700
                        throw new CantLocateClassException(parser, FIELD_CLASSOFITEMS_TAG, value);
701
                    }
702
                }
703

    
704
            } else if (name.equalsIgnoreCase(FIELD_CLASSOFVALUE_TAG)) {
705
                if (field.getType() == DataTypes.DYNOBJECT) {
706
                    this.postLoadActions.add(new SetDynClassOfValueAction(field, value));
707
                } else {
708
                    try {
709
                        Class klass;
710
                        klass = Class.forName(value, true, loader);
711
                        field.setClassOfValue(klass);
712
                    } catch (DynFieldIsNotAContainerException e) {
713
                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
714
                        throw new IncompatibleAttributeValueException(parser,
715
                                FIELD_NAME_TAG);
716
                    } catch (ClassNotFoundException e) {
717
                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
718
                        throw new CantLocateClassException(parser, FIELD_CLASSOFVALUE_TAG, value);
719
                    }
720
                }
721

    
722
            } else if (name.equalsIgnoreCase(FIELD_AVALILABLEVALUES_TAG)) {
723
                // Do nothing
724

    
725
            } else {
726
                throw new UnexpectedTagOrAttributeException(parser, name);
727
            }
728
        }
729

    
730
        try {
731
            //
732
            // Coerce the min/max/default/available values to the type of
733
            // the field
734
            //
735
            if (availableValues != null && !availableValues.isEmpty()) {
736
                for (int i = 0; i < availableValues.size(); i++) {
737
                    PairValueLabel pair = (PairValueLabel) availableValues
738
                            .get(i);
739
                    if (pair.label == null) {
740
                        if (pair.value == null) {
741
                            pair.label = "null";
742
                        } else {
743
                            pair.label = pair.value.toString();
744
                        }
745
                    }
746
                    availableValues.set(i,
747
                            new DynObjectValueItem(field.coerce(pair.value),
748
                                    pair.label));
749
                }
750
                field.setAvailableValues(availableValues);
751
            }
752
            if (tagsValues != null && !tagsValues.isEmpty()) {
753
                for (int i = 0; i < tagsValues.size(); i++) {
754
                    PairValueLabel pair = (PairValueLabel) tagsValues.get(i);
755
                    if (pair.label != null) {
756
                        field.getTags().set(pair.label, pair.value);
757
                    }
758
                }
759
            }
760
            field.setMaxValue(field.coerce(values.get(FIELD_MAXVALUE_TAG)));
761
            field.setMinValue(field.coerce(values.get(FIELD_MINVALUE_TAG)));
762
            field.setDefaultFieldValue(field.coerce(values
763
                    .get(FIELD_DEFAULTVALUE_TAG)));
764
        } catch (CoercionException e) {
765
            throw new ParseCoerceException(e, parser);
766
        }
767
    }
768

    
769
    private class PairValueLabel {
770

    
771
        String label = null;
772
        String value = null;
773
    }
774

    
775
    private PairValueLabel importValueItem(XmlPullParser parser, String attributeName)
776
            throws XmlPullParserException, IOException {
777
        PairValueLabel pair = new PairValueLabel();
778

    
779
        if (parser.getName().equalsIgnoreCase(VALUEITEM_TAG)) {
780
            parser.require(XmlPullParser.START_TAG, null, VALUEITEM_TAG);
781
            for (int i = 0; i < parser.getAttributeCount(); i++) {
782
                String name = parser.getAttributeName(i);
783
                if (name.equalsIgnoreCase(attributeName)) {
784
                    pair.label = this.getAttributeValue(parser, i);
785
                } else if (name.equalsIgnoreCase(VALUEITEM_VALUE_TAG)) {
786
                    pair.value = this.getAttributeValue(parser, i);
787
                } else {
788
                    throw new UnexpectedTagOrAttributeException(parser, name);
789
                }
790
            }
791
            parser.nextTag();
792

    
793
            while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
794
                    .getName().equals(VALUEITEM_TAG))) {
795
                checkEndDocument(parser);
796
                parser.require(XmlPullParser.START_TAG, null, null);
797
                String name = parser.getName();
798
                if (name.equalsIgnoreCase(attributeName)) {
799
                    pair.label = this.nextText(parser);
800
                } else if (name.equalsIgnoreCase(VALUEITEM_VALUE_TAG)) {
801
                    pair.value = this.nextText(parser);
802
                } else {
803
                    break;
804
                }
805
                parser.require(XmlPullParser.END_TAG, null, name);
806
                parser.nextTag();
807
            }
808
            parser.require(XmlPullParser.END_TAG, null, VALUEITEM_TAG);
809
        } else {
810
            parser.require(XmlPullParser.START_TAG, null, VALUEITEM_VALUE_TAG);
811
            for (int i = 0; i < parser.getAttributeCount(); i++) {
812
                String name = parser.getAttributeName(i);
813
                if (name.equalsIgnoreCase(attributeName)) {
814
                    pair.label = parser.getAttributeValue(i);
815
                } else if (name.equalsIgnoreCase(VALUEITEM_VALUE_TAG)) {
816
                    pair.value = this.getAttributeValue(parser, i);
817
                } else {
818
                    throw new UnexpectedTagOrAttributeException(parser, name);
819
                }
820
            }
821
            if (pair.value == null) {
822
                pair.value = parser.nextText();
823
            } else {
824
                pair.value += parser.nextText();
825
            }
826
            parser.require(XmlPullParser.END_TAG, null, VALUEITEM_VALUE_TAG);
827
        }
828
        return pair;
829
    }
830

    
831
    private void checkEndDocument(XmlPullParser parser)
832
            throws XmlPullParserException {
833
        if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
834
            throw new UnexpectedTagOrAttributeException(parser,
835
                    "(end-of-document)");
836
        }
837

    
838
    }
839

    
840
    public static abstract class ImportDynClassesException extends
841
            BaseRuntimeException {
842

    
843
        /**
844
         *
845
         */
846
        private static final long serialVersionUID = 3346283395112730192L;
847

    
848
        /**
849
         * Don't call this constructor form subclasses.
850
         *
851
         * @param parser
852
         */
853
        public ImportDynClassesException(XmlPullParser parser) {
854
            super(
855
                    "Error importing classes from file at line %(line) column %(column).",
856
                    "_Error_importing_classes_from_file_at_line_XlineX_column_XcolumnX",
857
                    serialVersionUID);
858
        }
859

    
860
        protected ImportDynClassesException(XmlPullParser parser, String msg,
861
                String key, long code) {
862
            super(
863
                    "Error importing classes from file at line %(line) column %(column). "
864
                    + msg, key, code);
865
            this.setValue("line", new Integer(parser.getLineNumber()));
866
            this.setValue("column", new Integer(parser.getColumnNumber()));
867
        }
868
    }
869

    
870
    public static class DuplicateDynClassException extends
871
            ImportDynClassesException {
872

    
873
        /**
874
         *
875
         */
876
        private static final long serialVersionUID = 3653024321140806121L;
877

    
878
        public DuplicateDynClassException(XmlPullParser parser, String name) {
879
            super(parser, "Duplicate DynClass definition for '%(name)'.",
880
                    "_Duplicate_DynClass_definition_for_XnameX",
881
                    serialVersionUID);
882
            this.setValue("name", name);
883
        }
884
    }
885

    
886
    public static class InvalidFieldTypeException extends
887
            ImportDynClassesException {
888

    
889
        /**
890
         *
891
         */
892
        private static final long serialVersionUID = 8501343258053356775L;
893

    
894
        public InvalidFieldTypeException(XmlPullParser parser, String value) {
895
            super(parser, "Invalid field type '%(value)'.",
896
                    "_Invalid_field_type_XvalueX", serialVersionUID);
897
            this.setValue("value", value);
898
        }
899
    }
900

    
901
    public static class UnexpectedTagOrAttributeException extends
902
            ImportDynClassesException {
903

    
904
        /**
905
         *
906
         */
907
        private static final long serialVersionUID = -808282903423455613L;
908

    
909
        public UnexpectedTagOrAttributeException(XmlPullParser parser,
910
                String tag) {
911
            super(parser, "Unexpected tag or attribute '%(tag)'.",
912
                    "_Unexpected_tag_or_attribute_XtagX", serialVersionUID);
913
            this.setValue("tag", tag);
914
        }
915
    }
916

    
917
    public static class NeedTagOrAttributeException extends
918
            ImportDynClassesException {
919

    
920
        /**
921
         *
922
         */
923
        private static final long serialVersionUID = -808282903423455613L;
924

    
925
        public NeedTagOrAttributeException(XmlPullParser parser, String tag) {
926
            super(parser, "Need tag or attribute '%(tag)'.",
927
                    "_Need_tag_or_attribute_XtagX", serialVersionUID);
928
            this.setValue("tag", tag);
929
        }
930
    }
931

    
932
    public static class CantLocateClassException extends
933
            ImportDynClassesException {
934

    
935
        /**
936
         *
937
         */
938
        private static final long serialVersionUID = 5733585544096433612L;
939

    
940
        public CantLocateClassException(XmlPullParser parser, String tagname) {
941
            super(parser, "Can't locate class named in attribute '%(name)'.",
942
                    "_Cant_locate_class_XnameX", serialVersionUID);
943
            this.setValue("name", tagname);
944
        }
945

    
946
        public CantLocateClassException(XmlPullParser parser, String tagname,
947
                String className) {
948
            super(parser, "Can't locate class named in attribute '%(name)' "
949
                    + "whose name is '%(className)'.", "_Cant_locate_class_XnameX",
950
                    serialVersionUID);
951
            this.setValue("name", tagname);
952
            this.setValue("className", className);
953
        }
954
    }
955

    
956
    public static class CantLocateDynClassException extends
957
            ImportDynClassesException {
958

    
959
        /**
960
         *
961
         */
962
        private static final long serialVersionUID = 6286170415562358806L;
963

    
964
        public CantLocateDynClassException(XmlPullParser parser, String tagname) {
965
            super(parser,
966
                    "Can't locate DynClass '%(name). Look at the extends tag.",
967
                    "_Cant_locate_DynClass_XnameX", serialVersionUID);
968
            this.setValue("name", tagname);
969
        }
970
    }
971

    
972
    public static class IncompatibleAttributeValueException extends
973
            ImportDynClassesException {
974

    
975
        /**
976
         *
977
         */
978
        private static final long serialVersionUID = 2646530094487375049L;
979

    
980
        public IncompatibleAttributeValueException(XmlPullParser parser,
981
                String name) {
982
            super(parser, "Incompatible attribute value for field '%(name)'.",
983
                    "_Incompatible_attribute_value_for_field_XnameX",
984
                    serialVersionUID);
985
            this.setValue("name", name);
986
        }
987

    
988
        public IncompatibleAttributeValueException(XmlPullParser parser,
989
                String name, String value) {
990
            super(
991
                    parser,
992
                    "Incompatible attribute value '%(value)', for field '%(name)'.",
993
                    "_Incompatible_attribute_value_for_field_XnameX",
994
                    serialVersionUID);
995
            this.setValue("name", name);
996
            this.setValue("value", value);
997
        }
998
    }
999

    
1000
    public static class ParseCoerceException extends ImportDynClassesException {
1001

    
1002
        /**
1003
         *
1004
         */
1005
        private static final long serialVersionUID = 1447718822981628834L;
1006

    
1007
        public ParseCoerceException(Throwable cause, XmlPullParser parser) {
1008
            super(parser, "Can't convert value.", "_Cant_convert_value",
1009
                    serialVersionUID);
1010
            this.initCause(cause);
1011
        }
1012
    }
1013

    
1014
    public static class WrongVersionException extends ImportDynClassesException {
1015

    
1016
        private static final long serialVersionUID = 6620589308398698367L;
1017

    
1018
        public WrongVersionException(XmlPullParser parser) {
1019
            super(parser, "Wrong format version.", "_Wrong_format_version",
1020
                    serialVersionUID);
1021
        }
1022
    }
1023

    
1024
}