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

History | View | Annotate | Download (26.2 KB)

1
package org.gvsig.tools.dynobject.impl;
2

    
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.util.ArrayList;
6
import java.util.HashMap;
7
import java.util.Iterator;
8
import java.util.List;
9
import java.util.Map;
10

    
11
import org.slf4j.Logger;
12
import org.slf4j.LoggerFactory;
13
import org.xmlpull.v1.XmlPullParser;
14
import org.xmlpull.v1.XmlPullParserException;
15
import org.xmlpull.v1.XmlPullParserFactory;
16

    
17
import org.gvsig.tools.ToolsLocator;
18
import org.gvsig.tools.dataTypes.CoercionException;
19
import org.gvsig.tools.dataTypes.DataTypes;
20
import org.gvsig.tools.dynobject.DynClass;
21
import org.gvsig.tools.dynobject.DynClassName;
22
import org.gvsig.tools.dynobject.DynField;
23
import org.gvsig.tools.dynobject.DynObjectManager;
24
import org.gvsig.tools.dynobject.DynObjectRuntimeException;
25
import org.gvsig.tools.dynobject.DynObjectValueItem;
26
import org.gvsig.tools.dynobject.exception.DynFieldIsNotAContainerException;
27
import org.gvsig.tools.exception.BaseRuntimeException;
28
import org.gvsig.tools.exception.ListBaseException;
29

    
30
public class DynClassImportHelper {
31

    
32
        private static final Logger LOG = LoggerFactory
33
                        .getLogger(DynClassImportHelper.class);
34

    
35
        private static final String VERSION_VALUE = "1.0.0";
36

    
37
        private static final String DEFINITIONS_TAG = "definitions";
38
        private static final String VERSION_TAG = "version";
39
        private static final String CLASSES_TAG = "classes";
40

    
41
        private static final String CLASS_TAG = "class";
42
        private static final String CLASS_NAME_TAG = "name";
43
        private static final String CLASS_NAMESPACE_TAG = "namespace";
44
        private static final String CLASS_DESCRIPTION_TAG = "description";
45
        private static final String CLASS_SUPERCLASSNAMES_TAG = "superClassNames";
46
        private static final String CLASS_SUPERCLASSNAME_TAG = "superClassName";
47
        private static final String CLASS_EXTENDS_TAG = "extends";
48
        private static final String CLASS_EXTENDS_CLASS_TAG = "class";
49
        private static final String CLASS_FIELDS_TAG = "fields";
50

    
51
        private static final String FIELD_TAG = "field";
52
        private static final String FIELD_NAME_TAG = "name";
53
        private static final String FIELD_DESCRIPTION_TAG = "description";
54
        private static final String FIELD_SUBTYPE_TAG = "subtype";
55
        private static final String FIELD_TYPE_TAG = "type";
56
        private static final String FIELD_ISMANDATORY_TAG = "mandatory";
57
        private static final String FIELD_ISPERSISTENT_TAG = "persistent";
58
        private static final String FIELD_MINVALUE_TAG = "minValue";
59
        private static final String FIELD_MAXVALUE_TAG = "maxValue";
60
        private static final String FIELD_CLASSOFVALUE_TAG = "classOfValue";
61
        private static final String FIELD_CLASSOFITEMS_TAG = "classOfItems";
62
        private static final String FIELD_DEFAULTVALUE_TAG = "defaultValue";
63
        // private static final String FIELD_TYPEOFAVALILABLEVALUES_TAG =
64
        // "typeOfAvailableValues";
65
        private static final String FIELD_AVALILABLEVALUES_TAG = "availableValues";
66
        private static final String FIELD_GROUP_TAG = "group";
67
        private static final String FIELD_ORDER_TAG = "order";
68
        private static final String FIELD_HIDDEN_TAG = "hidden";
69

    
70
        private static final String VALUEITEM_TAG = "valueItem";
71
        private static final String VALUEITEM_LABEL_TAG = "label";
72
        private static final String VALUEITEM_VALUE_TAG = "value";
73

    
74
        private DynObjectManager manager = ToolsLocator.getDynObjectManager();
75

    
76
        private String getNullWhenEmptyString(String value) {
77
                if (value != null) {
78
                        if (value.trim().length() == 0) {
79
                                return null;
80
                        }
81
                }
82
                return value;
83

    
84
        }
85

    
86
        private String nextText(XmlPullParser parser)
87
                        throws XmlPullParserException, IOException {
88
                return getNullWhenEmptyString(parser.nextText());
89
        }
90

    
91
        private String getAttributeValue(XmlPullParser parser, int i)
92
                        throws XmlPullParserException, IOException {
93
                return getNullWhenEmptyString(parser.getAttributeValue(i));
94
        }
95

    
96
        public Map importDefinitions(InputStream resource, ClassLoader loader,
97
                        String defaultNamespace) throws XmlPullParserException, IOException {
98

    
99
                XmlPullParserFactory factory = XmlPullParserFactory.newInstance(
100
                                ToolsLocator.getInstance().getXmlPullParserFactoryClassNames(),
101
                                null);
102

    
103
                XmlPullParser parser = factory.newPullParser();
104

    
105
                parser.setInput(resource, null);
106

    
107
                return importDefinitions(parser, loader, defaultNamespace);
108
        }
109

    
110
        private class Definitions extends HashMap implements Map {
111

    
112
                /**
113
                 * 
114
                 */
115
                private static final long serialVersionUID = -3322643637478345069L;
116

    
117
                public Object put(Object key, Object value) {
118
                        return super.put(((String) key).toLowerCase(), value);
119
                }
120

    
121
                public Object get(Object theName) {
122
                        DynClass definition;
123
                        definition = (DynClass) super.get(((String) theName).toLowerCase());
124
                        if (definition != null) {
125
                                return definition;
126
                        }
127
                        // No ha encontrado la clase pedida, podria ser que el namespace
128
                        // no coincida, vamos a buscarla ignorando el namespace en caso
129
                        // de que este no se haya indicado.
130
                        DynClassName name = manager.createDynClassName((String) theName);
131
                        if (name.getNamespace() == null) {
132
                                // No han especificado namespace, asi que busco la primera
133
                                // que tenga como nombre el indicado independientemente del
134
                                // namespace que tenga.
135
                                Iterator it = this.values().iterator();
136
                                while (it.hasNext()) {
137
                                        definition = (DynClass) it.next();
138
                                        if (definition.getName().equalsIgnoreCase(name.getName())) {
139
                                                return definition;
140
                                        }
141
                                }
142
                        } else {
143
                                // Han especificaso un namespace, asi que voy a buscar una que
144
                                // no tenga namespace y su nombre concuerde.
145
                                Iterator it = this.values().iterator();
146
                                while (it.hasNext()) {
147
                                        definition = (DynClass) it.next();
148
                                        if (definition.getNamespace() == null
149
                                                        && definition.getName().equalsIgnoreCase(
150
                                                                        name.getName())) {
151
                                                return definition;
152
                                        }
153
                                }
154
                        }
155
                        return null;
156
                }
157

    
158
                public boolean containsKey(Object key) {
159
                        String lowerKey = ((String) key).toLowerCase();
160
                        if (super.containsKey(lowerKey)) {
161
                                return true;
162
                        }
163
                        Object value = this.get(lowerKey);
164
                        return value != null;
165
                }
166
        }
167

    
168
        public Map importDefinitions(XmlPullParser parser, ClassLoader loader,
169
                        String defaultNamespace) throws XmlPullParserException, IOException {
170
                Map dynClasses = new Definitions();
171
                String version = null;
172

    
173
                if (loader == null) {
174
                        loader = this.getClass().getClassLoader();
175
                }
176
                parser.nextTag();
177
                parser.require(XmlPullParser.START_TAG, null, DEFINITIONS_TAG);
178
                for (int i = 0; i < parser.getAttributeCount(); i++) {
179
                        String name = parser.getAttributeName(i);
180
                        if (name.equalsIgnoreCase(VERSION_TAG)) {
181
                                version = this.getAttributeValue(parser, i);
182
                        } else {
183
                                throw new WrongVersionException(parser);
184
                        }
185
                }
186
                parser.nextTag();
187
                if (parser.getName().equalsIgnoreCase(VERSION_TAG)) {
188
                        parser.require(XmlPullParser.START_TAG, null, VERSION_TAG);
189
                        version = parser.nextText();
190
                        if (!version.trim().equals(VERSION_VALUE)) {
191
                                throw new UnsupportedClassVersionError();
192
                        }
193
                        parser.require(XmlPullParser.END_TAG, "", VERSION_TAG);
194
                        parser.nextTag();
195
                }
196

    
197
                parser.require(XmlPullParser.START_TAG, "", CLASSES_TAG);
198
                parser.nextTag();
199
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
200
                                .getName().equals(CLASSES_TAG))) {
201
                        checkEndDocument(parser);
202
                        DynClass dynClass = importDynClass(parser, loader,
203
                                        defaultNamespace, dynClasses);
204
                        try {
205
                                ((DefaultDynClass) dynClass).check();
206
                        } catch (ListBaseException e) {
207
                                throw new DynObjectRuntimeException(e);
208
                        }
209
                        if (dynClasses.get(dynClass.getFullName()) != null) {
210
                                throw new DuplicateDynClassException(parser,
211
                                                dynClass.getFullName());
212
                        }
213
                        dynClasses.put(dynClass.getFullName(), dynClass);
214
                }
215
                parser.require(XmlPullParser.END_TAG, "", CLASSES_TAG);
216
                parser.nextTag();
217

    
218
                parser.require(XmlPullParser.END_TAG, "", DEFINITIONS_TAG);
219
                parser.next();
220

    
221
                parser.require(XmlPullParser.END_DOCUMENT, null, null);
222
                LOG.debug("Imported classes {}", new Object[] { getKeys(dynClasses) });
223
                return dynClasses;
224
        }
225

    
226
        private String getKeys(Map theMap) {
227
                List l = new ArrayList(theMap.keySet());
228
                return l.toString();
229
        }
230

    
231
        private DynClass importDynClass(XmlPullParser parser, ClassLoader loader,
232
                        String defaultNamespace, Map classes)
233
                        throws XmlPullParserException, IOException {
234
                DynObjectManager manager = ToolsLocator.getDynObjectManager();
235
                DynClass dynClass;
236
                List superClasses = new ArrayList();
237
                Map values = new HashMap();
238

    
239
                parser.require(XmlPullParser.START_TAG, null, CLASS_TAG);
240
                //
241
                // Collect class attributes from tag attributes
242
                //
243
                for (int i = 0; i < parser.getAttributeCount(); i++) {
244
                        values.put(parser.getAttributeName(i),
245
                                        this.getAttributeValue(parser, i));
246
                }
247
                parser.nextTag();
248

    
249
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
250
                                .getName().equals(CLASSES_TAG))) {
251
                        checkEndDocument(parser);
252

    
253
                        parser.require(XmlPullParser.START_TAG, null, null);
254
                        String tagName = parser.getName();
255
                        if (tagName.equalsIgnoreCase(CLASS_DESCRIPTION_TAG)) {
256
                                values.put(CLASS_DESCRIPTION_TAG, this.nextText(parser));
257

    
258
                        } else if (tagName.equalsIgnoreCase(CLASS_NAME_TAG)) {
259
                                values.put(CLASS_NAME_TAG, this.nextText(parser));
260

    
261
                        } else if (tagName.equalsIgnoreCase(CLASS_NAMESPACE_TAG)) {
262
                                values.put(CLASS_NAMESPACE_TAG, this.nextText(parser));
263

    
264
                        } else if (tagName.equalsIgnoreCase(CLASS_SUPERCLASSNAMES_TAG)) {
265
                                parser.nextTag();
266
                                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
267
                                                .getName().equals(CLASS_SUPERCLASSNAMES_TAG))) {
268
                                        checkEndDocument(parser);
269
                                        parser.require(XmlPullParser.START_TAG, "",
270
                                                        CLASS_SUPERCLASSNAME_TAG);
271
                                        superClasses.add(manager.createDynClassName(
272
                                                        defaultNamespace, this.nextText(parser)));
273
                                        parser.require(XmlPullParser.END_TAG, null,
274
                                                        CLASS_SUPERCLASSNAME_TAG);
275
                                        parser.nextTag();
276
                                }
277

    
278
                        } else if (tagName.equalsIgnoreCase(CLASS_EXTENDS_TAG)) {
279
                                parser.nextTag();
280
                                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
281
                                                .getName().equals(CLASS_EXTENDS_TAG))) {
282
                                        checkEndDocument(parser);
283
                                        superClasses
284
                                                        .add(importSuperClass(parser, defaultNamespace));
285
                                        parser.nextTag();
286
                                }
287
                        } else {
288
                                break;
289
                        }
290
                        parser.require(XmlPullParser.END_TAG, null, tagName);
291
                        parser.nextTag();
292
                }
293
                parser.require(XmlPullParser.START_TAG, null, CLASS_FIELDS_TAG);
294
                parser.nextTag();
295

    
296
                //
297
                // Create dynclass
298
                //
299
                if (values.get(CLASS_NAME_TAG) == null) {
300
                        throw new NeedTagOrAttributeException(parser, CLASS_NAME_TAG);
301
                }
302
                if (values.get(CLASS_NAMESPACE_TAG) == null) {
303
                        values.put(CLASS_NAMESPACE_TAG, defaultNamespace);
304
                }
305
                dynClass = manager.createDynClass(
306
                                (String) values.get(CLASS_NAMESPACE_TAG),
307
                                (String) values.get(CLASS_NAME_TAG),
308
                                (String) values.get(CLASS_DESCRIPTION_TAG));
309
                for (int i = 0; i < superClasses.size(); i++) {
310
                        DynClassName superClass = (DynClassName) superClasses.get(i);
311
                        if (superClass.getName() == null) {
312
                                throw new NeedTagOrAttributeException(parser, CLASS_NAME_TAG);
313
                        }
314
                        DynClass superDynClass = (DynClass) classes.get(superClass
315
                                        .getFullName());
316
                        if (superDynClass == null) {
317
                                superDynClass = ToolsLocator.getDynObjectManager().get(
318
                                                superClass.getNamespace(), superClass.getName());
319
                                if (superDynClass == null) {
320
                                        throw new CantLocateDynClassException(parser,
321
                                                        superClass.getFullName());
322
                                }
323
                        }
324
                        dynClass.extend(superDynClass);
325
                }
326

    
327
                //
328
                // Parse and load fields of dynclass
329
                //
330
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
331
                                .getName().equals(CLASS_FIELDS_TAG))) {
332
                        checkEndDocument(parser);
333
                        importDynField(parser, dynClass, loader);
334
                        parser.nextTag();
335
                }
336
                parser.require(XmlPullParser.END_TAG, null, CLASS_FIELDS_TAG);
337
                parser.nextTag();
338

    
339
                parser.require(XmlPullParser.END_TAG, null, CLASS_TAG);
340
                parser.nextTag();
341
                return dynClass;
342
        }
343

    
344
        private DynClassName importSuperClass(XmlPullParser parser,
345
                        String defaultNamespace) throws XmlPullParserException, IOException {
346

    
347
                String name = null;
348
                String namespace = defaultNamespace;
349

    
350
                parser.require(XmlPullParser.START_TAG, null, CLASS_EXTENDS_CLASS_TAG);
351
                for (int i = 0; i < parser.getAttributeCount(); i++) {
352
                        String attrname = parser.getAttributeName(i);
353
                        if (attrname.equalsIgnoreCase(CLASS_NAME_TAG)) {
354
                                name = this.getAttributeValue(parser, i);
355
                        } else if (attrname.equalsIgnoreCase(CLASS_NAMESPACE_TAG)) {
356
                                namespace = this.getAttributeValue(parser, i);
357
                        } else {
358
                                throw new UnexpectedTagOrAttributeException(parser, attrname);
359
                        }
360
                }
361
                if (name == null) {
362
                        name = this.nextText(parser);
363
                } else {
364
                        parser.nextTag();
365
                }
366
                parser.require(XmlPullParser.END_TAG, null, CLASS_EXTENDS_CLASS_TAG);
367
                DynClassName dynClassName = manager.createDynClassName(namespace, name);
368
                return dynClassName;
369
        }
370

    
371
        private void importDynField(XmlPullParser parser, DynClass dynClass,
372
                        ClassLoader loader) throws XmlPullParserException, IOException {
373
                DynField field;
374
                List availableValues = null;
375
                Map values = new HashMap();
376

    
377
                parser.require(XmlPullParser.START_TAG, null, FIELD_TAG);
378
                //
379
                // Collect field attributes from tag attributes
380
                //
381
                for (int i = 0; i < parser.getAttributeCount(); i++) {
382
                        values.put(parser.getAttributeName(i),
383
                                        this.getAttributeValue(parser, i));
384
                }
385
                parser.nextTag();
386

    
387
                //
388
                // Collect field attributes from tags
389
                //
390
                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
391
                                .getName().equals(FIELD_TAG))) {
392
                        checkEndDocument(parser);
393

    
394
                        parser.require(XmlPullParser.START_TAG, null, null);
395
                        String name = parser.getName();
396
                        if (name.equalsIgnoreCase(FIELD_NAME_TAG)) {
397
                                values.put(FIELD_NAME_TAG, this.nextText(parser));
398

    
399
                        } else if (name.equalsIgnoreCase(FIELD_DESCRIPTION_TAG)) {
400
                                values.put(FIELD_DESCRIPTION_TAG, this.nextText(parser));
401

    
402
                        } else if (name.equalsIgnoreCase(FIELD_TYPE_TAG)) {
403
                                values.put(FIELD_TYPE_TAG, this.nextText(parser));
404

    
405
                        } else if (name.equalsIgnoreCase(FIELD_SUBTYPE_TAG)) {
406
                                values.put(FIELD_SUBTYPE_TAG, this.nextText(parser));
407

    
408
                        } else if (name.equalsIgnoreCase(FIELD_GROUP_TAG)) {
409
                                values.put(FIELD_GROUP_TAG, this.nextText(parser));
410

    
411
                        } else if (name.equalsIgnoreCase(FIELD_ORDER_TAG)) {
412
                                values.put(FIELD_ORDER_TAG, this.nextText(parser));
413

    
414
                        } else if (name.equalsIgnoreCase(FIELD_ISMANDATORY_TAG)) {
415
                                values.put(FIELD_ISMANDATORY_TAG, this.nextText(parser));
416

    
417
                        } else if (name.equalsIgnoreCase(FIELD_ISPERSISTENT_TAG)) {
418
                                values.put(FIELD_ISPERSISTENT_TAG, this.nextText(parser));
419

    
420
                        } else if (name.equalsIgnoreCase(FIELD_MINVALUE_TAG)) {
421
                                values.put(FIELD_MINVALUE_TAG, this.nextText(parser));
422

    
423
                        } else if (name.equalsIgnoreCase(FIELD_MAXVALUE_TAG)) {
424
                                values.put(FIELD_MAXVALUE_TAG, this.nextText(parser));
425

    
426
                        } else if (name.equalsIgnoreCase(FIELD_CLASSOFVALUE_TAG)) {
427
                                values.put(FIELD_CLASSOFVALUE_TAG, this.nextText(parser));
428

    
429
                        } else if (name.equalsIgnoreCase(FIELD_CLASSOFITEMS_TAG)) {
430
                                values.put(FIELD_CLASSOFITEMS_TAG, this.nextText(parser));
431

    
432
                        } else if (name.equalsIgnoreCase(FIELD_DEFAULTVALUE_TAG)) {
433
                                values.put(FIELD_DEFAULTVALUE_TAG, this.nextText(parser));
434

    
435
                        } else if (name.equalsIgnoreCase(FIELD_HIDDEN_TAG)) {
436
                                values.put(FIELD_HIDDEN_TAG, this.nextText(parser));
437

    
438
                        } else if (name.equalsIgnoreCase(FIELD_AVALILABLEVALUES_TAG)) {
439
                                parser.nextTag();
440
                                availableValues = new ArrayList();
441
                                while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
442
                                                .getName().equals(FIELD_AVALILABLEVALUES_TAG))) {
443
                                        checkEndDocument(parser);
444
                                        availableValues.add(importValueItem(parser));
445
                                        parser.nextTag();
446
                                }
447

    
448
                        } else {
449
                                break;
450
                        }
451
                        parser.require(XmlPullParser.END_TAG, null, name);
452
                        parser.nextTag();
453
                }
454
                parser.require(XmlPullParser.END_TAG, null, FIELD_TAG);
455

    
456
                if (values.get(FIELD_NAME_TAG) == null) {
457
                        throw new NeedTagOrAttributeException(parser, FIELD_NAME_TAG);
458
                }
459

    
460
                //
461
                // Create the field
462
                //
463
                field = dynClass.addDynField((String) values.get(FIELD_NAME_TAG));
464

    
465
                //
466
                // Setting type and subtype first
467
                //
468

    
469
                String name = FIELD_TYPE_TAG;
470
                String value = (String) values.get(name);
471
                if (value != null) {
472
                        int type = ToolsLocator.getDataTypesManager().getType(value);
473
                        if (type == DataTypes.INVALID) {
474
                                throw new InvalidFieldTypeException(parser, value);
475
                        }
476
                        field.setType(type);
477
                        name = FIELD_CLASSOFVALUE_TAG;
478
                        value = (String) values.get(name);
479
                        if (value != null) {
480
                                try {
481
                                        Class klass;
482
                                        LOG.info("Intentando cargar clase '" + value + "'.");
483
                                        klass = Class.forName(value, true, loader);
484
                                        field.setClassOfValue(klass);
485
                                } catch (DynFieldIsNotAContainerException e) {
486
                                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
487
                                        throw new IncompatibleAttributeValueException(parser,
488
                                                        FIELD_NAME_TAG);
489
                                } catch (ClassNotFoundException e) {
490
                                        LOG.warn("No se ha encontrado la clase '" + value + "'.", e);
491
                                        throw new CantLocateClassException(parser, FIELD_NAME_TAG);
492
                                }
493
                        }
494
                        name = FIELD_CLASSOFITEMS_TAG;
495
                        value = (String) values.get(name);
496
                        if (value != null) {
497
                                try {
498
                                        Class klass;
499
                                        klass = Class.forName(value, true, loader);
500
                                        field.setClassOfValue(klass);
501
                                } catch (DynFieldIsNotAContainerException e) {
502
                                        throw new IncompatibleAttributeValueException(parser,
503
                                                        FIELD_NAME_TAG);
504
                                } catch (ClassNotFoundException e) {
505
                                        throw new CantLocateClassException(parser, FIELD_NAME_TAG);
506
                                }
507
                        }
508
                }
509

    
510
                name = FIELD_SUBTYPE_TAG;
511
                value = (String) values.get(name);
512
                if (value != null) {
513
                        try {
514
                                field.setSubtype(value);
515
                        } catch (IllegalArgumentException e) {
516
                                // Ignore exception
517
                        }
518
                }
519

    
520
                //
521
                // Load other values in the field
522
                //
523
                Iterator names = values.keySet().iterator();
524
                while (names.hasNext()) {
525
                        name = (String) names.next();
526
                        value = (String) values.get(name);
527
                        if (value == null) {
528
                                continue;
529
                        }
530
                        if (name.equalsIgnoreCase(FIELD_NAME_TAG)) {
531
                                // Do nothing
532

    
533
                        } else if (name.equalsIgnoreCase(FIELD_DESCRIPTION_TAG)) {
534
                                field.setDescription(value);
535

    
536
                        } else if (name.equalsIgnoreCase(FIELD_TYPE_TAG)) {
537
                                // Do nothing
538
                        } else if (name.equalsIgnoreCase(FIELD_SUBTYPE_TAG)) {
539
                                // Do nothing
540
                        } else if (name.equalsIgnoreCase(FIELD_GROUP_TAG)) {
541
                                field.setGroup(value);
542

    
543
                        } else if (name.equalsIgnoreCase(FIELD_ORDER_TAG)) {
544
                                field.setOrder(Integer.parseInt(value));
545

    
546
                        } else if (name.equalsIgnoreCase(FIELD_ISMANDATORY_TAG)) {
547
                                field.setMandatory(new Boolean(value).booleanValue());
548

    
549
                        } else if (name.equalsIgnoreCase(FIELD_ISPERSISTENT_TAG)) {
550
                                field.setPersistent(new Boolean(value).booleanValue());
551

    
552
                        } else if (name.equalsIgnoreCase(FIELD_HIDDEN_TAG)) {
553
                                field.setHidden(new Boolean(value).booleanValue());
554

    
555
                        } else if (name.equalsIgnoreCase(FIELD_MINVALUE_TAG)) {
556
                                // Do nothing
557

    
558
                        } else if (name.equalsIgnoreCase(FIELD_MAXVALUE_TAG)) {
559
                                // Do nothing
560

    
561
                        } else if (name.equalsIgnoreCase(FIELD_DEFAULTVALUE_TAG)) {
562
                                // Do nothing
563

    
564
                        } else if (name.equalsIgnoreCase(FIELD_AVALILABLEVALUES_TAG)) {
565
                                // Do nothing
566

    
567
                        } else if (name.equalsIgnoreCase(FIELD_CLASSOFVALUE_TAG)) {
568
                                // Do nothing
569

    
570
                        } else if (name.equalsIgnoreCase(FIELD_CLASSOFITEMS_TAG)) {
571
                                // Do nothing
572

    
573
                        } else {
574
                                throw new UnexpectedTagOrAttributeException(parser, name);
575
                        }
576
                }
577

    
578
                try {
579
                        //
580
                        // Coerce the min/max/default/available values to the type of
581
                        // the field
582
                        //
583
                        if (availableValues != null && !availableValues.isEmpty()) {
584
                                for (int i = 0; i < availableValues.size(); i++) {
585
                                        PairValueLabel pair = (PairValueLabel) availableValues
586
                                                        .get(i);
587
                                        if (pair.label == null) {
588
                                                if (pair.value == null) {
589
                                                        pair.label = "null";
590
                                                } else {
591
                                                        pair.label = pair.value.toString();
592
                                                }
593
                                        }
594
                                        availableValues.set(i,
595
                                                        new DynObjectValueItem(field.coerce(pair.value),
596
                                                                        pair.label));
597
                                }
598
                                field.setAvailableValues(availableValues);
599
                        }
600
                        field.setMaxValue(field.coerce(values.get(FIELD_MAXVALUE_TAG)));
601
                        field.setMinValue(field.coerce(values.get(FIELD_MINVALUE_TAG)));
602
                        field.setDefaultFieldValue(field.coerce(values
603
                                        .get(FIELD_DEFAULTVALUE_TAG)));
604
                } catch (CoercionException e) {
605
                        throw new ParseCoerceException(e, parser);
606
                }
607
        }
608

    
609
        private class PairValueLabel {
610
                String label = null;
611
                String value = null;
612
        }
613

    
614
        private PairValueLabel importValueItem(XmlPullParser parser)
615
                        throws XmlPullParserException, IOException {
616
                PairValueLabel pair = new PairValueLabel();
617

    
618
                if (parser.getName().equalsIgnoreCase(VALUEITEM_TAG)) {
619
                        parser.require(XmlPullParser.START_TAG, null, VALUEITEM_TAG);
620
                        for (int i = 0; i < parser.getAttributeCount(); i++) {
621
                                String name = parser.getAttributeName(i);
622
                                if (name.equalsIgnoreCase(VALUEITEM_LABEL_TAG)) {
623
                                        pair.label = this.getAttributeValue(parser, i);
624
                                } else if (name.equalsIgnoreCase(VALUEITEM_VALUE_TAG)) {
625
                                        pair.value = this.getAttributeValue(parser, i);
626
                                } else {
627
                                        throw new UnexpectedTagOrAttributeException(parser, name);
628
                                }
629
                        }
630
                        parser.nextTag();
631

    
632
                        while (!(parser.getEventType() == XmlPullParser.END_TAG && parser
633
                                        .getName().equals(VALUEITEM_TAG))) {
634
                                checkEndDocument(parser);
635
                                parser.require(XmlPullParser.START_TAG, null, null);
636
                                String name = parser.getName();
637
                                if (name.equalsIgnoreCase(VALUEITEM_LABEL_TAG)) {
638
                                        pair.label = this.nextText(parser);
639
                                } else if (name.equalsIgnoreCase(VALUEITEM_VALUE_TAG)) {
640
                                        pair.value = this.nextText(parser);
641
                                } else {
642
                                        break;
643
                                }
644
                                parser.require(XmlPullParser.END_TAG, null, name);
645
                                parser.nextTag();
646
                        }
647
                        parser.require(XmlPullParser.END_TAG, null, VALUEITEM_TAG);
648
                } else {
649
                        parser.require(XmlPullParser.START_TAG, null, VALUEITEM_VALUE_TAG);
650
                        for (int i = 0; i < parser.getAttributeCount(); i++) {
651
                                String name = parser.getAttributeName(i);
652
                                if (name.equalsIgnoreCase(VALUEITEM_LABEL_TAG)) {
653
                                        pair.label = parser.getAttributeValue(i);
654
                                } else {
655
                                        throw new UnexpectedTagOrAttributeException(parser, name);
656
                                }
657
                        }
658
                        pair.value = parser.nextText();
659
                        parser.require(XmlPullParser.END_TAG, null, VALUEITEM_VALUE_TAG);
660
                }
661
                return pair;
662
        }
663

    
664
        private void checkEndDocument(XmlPullParser parser)
665
                        throws XmlPullParserException {
666
                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {
667
                        throw new UnexpectedTagOrAttributeException(parser,
668
                                        "(end-of-document)");
669
                }
670

    
671
        }
672

    
673
        public static abstract class ImportDynClassesException extends
674
                        BaseRuntimeException {
675

    
676
                /**
677
                 * 
678
                 */
679
                private static final long serialVersionUID = 3346283395112730192L;
680

    
681
                /**
682
                 * Don't call this constructor form subclasses.
683
                 * 
684
                 * @param parser
685
                 */
686
                public ImportDynClassesException(XmlPullParser parser) {
687
                        super(
688
                                        "Error importing classes from file at line %(line) column %(column).",
689
                                        "_Error_importing_classes_from_file_at_line_XlineX_column_XcolumnX",
690
                                        serialVersionUID);
691
                }
692

    
693
                protected ImportDynClassesException(XmlPullParser parser, String msg,
694
                                String key, long code) {
695
                        super(
696
                                        "Error importing classes from file at line %(line) column %(column). "
697
                                                        + msg, key, code);
698
                        this.setValue("line", new Integer(parser.getLineNumber()));
699
                        this.setValue("column", new Integer(parser.getColumnNumber()));
700
                }
701
        }
702

    
703
        public static class DuplicateDynClassException extends
704
                        ImportDynClassesException {
705
                /**
706
                 * 
707
                 */
708
                private static final long serialVersionUID = 3653024321140806121L;
709

    
710
                public DuplicateDynClassException(XmlPullParser parser, String name) {
711
                        super(parser, "Duplicate DynClass definition for '%(name)'.",
712
                                        "_Duplicate_DynClass_definition_for_XnameX",
713
                                        serialVersionUID);
714
                        this.setValue("name", name);
715
                }
716
        }
717

    
718
        public static class InvalidFieldTypeException extends
719
                        ImportDynClassesException {
720

    
721
                /**
722
                 * 
723
                 */
724
                private static final long serialVersionUID = 8501343258053356775L;
725

    
726
                public InvalidFieldTypeException(XmlPullParser parser, String value) {
727
                        super(parser, "Invalid field type '%(value)'.",
728
                                        "_Invalid_field_type_XvalueX", serialVersionUID);
729
                        this.setValue("value", value);
730
                }
731
        }
732

    
733
        public static class UnexpectedTagOrAttributeException extends
734
                        ImportDynClassesException {
735
                /**
736
                 * 
737
                 */
738
                private static final long serialVersionUID = -808282903423455613L;
739

    
740
                public UnexpectedTagOrAttributeException(XmlPullParser parser,
741
                                String tag) {
742
                        super(parser, "Unexpected tag or attribute '%(tag)'.",
743
                                        "_Unexpected_tag_or_attribute_XtagX", serialVersionUID);
744
                        this.setValue("tag", tag);
745
                }
746
        }
747

    
748
        public static class NeedTagOrAttributeException extends
749
                        ImportDynClassesException {
750
                /**
751
                 * 
752
                 */
753
                private static final long serialVersionUID = -808282903423455613L;
754

    
755
                public NeedTagOrAttributeException(XmlPullParser parser, String tag) {
756
                        super(parser, "Need tag or attribute '%(tag)'.",
757
                                        "_Need_tag_or_attribute_XtagX", serialVersionUID);
758
                        this.setValue("tag", tag);
759
                }
760
        }
761

    
762
        public static class CantLocateClassException extends
763
                        ImportDynClassesException {
764
                /**
765
                 * 
766
                 */
767
                private static final long serialVersionUID = 5733585544096433612L;
768

    
769
                public CantLocateClassException(XmlPullParser parser, String tagname) {
770
                        super(parser, "Can't locate class '%(name).",
771
                                        "_Cant_locate_class_XnameX", serialVersionUID);
772
                        this.setValue("name", tagname);
773
                }
774
        }
775

    
776
        public static class CantLocateDynClassException extends
777
                        ImportDynClassesException {
778

    
779
                /**
780
                 * 
781
                 */
782
                private static final long serialVersionUID = 6286170415562358806L;
783

    
784
                public CantLocateDynClassException(XmlPullParser parser, String tagname) {
785
                        super(parser,
786
                                        "Can't locate DynClass '%(name). Look at the extends tag.",
787
                                        "_Cant_locate_DynClass_XnameX", serialVersionUID);
788
                        this.setValue("name", tagname);
789
                }
790
        }
791

    
792
        public static class IncompatibleAttributeValueException extends
793
                        ImportDynClassesException {
794
                /**
795
                 * 
796
                 */
797
                private static final long serialVersionUID = 2646530094487375049L;
798

    
799
                public IncompatibleAttributeValueException(XmlPullParser parser,
800
                                String name) {
801
                        super(parser, "incompatible attribute value for field '%(name).",
802
                                        "_Incompatible_attribute_value_for_field_XnameX",
803
                                        serialVersionUID);
804
                        this.setValue("name", name);
805
                }
806
        }
807

    
808
        public static class ParseCoerceException extends ImportDynClassesException {
809

    
810
                /**
811
                 * 
812
                 */
813
                private static final long serialVersionUID = 1447718822981628834L;
814

    
815
                public ParseCoerceException(Throwable cause, XmlPullParser parser) {
816
                        super(parser, "Can't convert value.", "_Cant_convert_value",
817
                                        serialVersionUID);
818
                        this.initCause(cause);
819
                }
820
        }
821

    
822
        public static class WrongVersionException extends ImportDynClassesException {
823

    
824
                private static final long serialVersionUID = 6620589308398698367L;
825

    
826
                public WrongVersionException(XmlPullParser parser) {
827
                        super(parser, "Wrong format version.", "_Wrong_format_version",
828
                                        serialVersionUID);
829
                }
830
        }
831

    
832
}