~ubuntu-branches/ubuntu/utopic/gridengine/utopic

« back to all changes in this revision

Viewing changes to source/libs/jgdi/src/com/sun/grid/jgdi/configuration/xml/XMLUtil.java

  • Committer: Bazaar Package Importer
  • Author(s): Mark Hymers
  • Date: 2008-06-25 22:36:13 UTC
  • Revision ID: james.westby@ubuntu.com-20080625223613-tvd9xlhuoct9kyhm
Tags: upstream-6.2~beta2
ImportĀ upstreamĀ versionĀ 6.2~beta2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*___INFO__MARK_BEGIN__*/
 
2
/*************************************************************************
 
3
 *
 
4
 *  The Contents of this file are made available subject to the terms of
 
5
 *  the Sun Industry Standards Source License Version 1.2
 
6
 *
 
7
 *  Sun Microsystems Inc., March, 2001
 
8
 *
 
9
 *
 
10
 *  Sun Industry Standards Source License Version 1.2
 
11
 *  =================================================
 
12
 *  The contents of this file are subject to the Sun Industry Standards
 
13
 *  Source License Version 1.2 (the "License"); You may not use this file
 
14
 *  except in compliance with the License. You may obtain a copy of the
 
15
 *  License at http://gridengine.sunsource.net/Gridengine_SISSL_license.html
 
16
 *
 
17
 *  Software provided under this License is provided on an "AS IS" basis,
 
18
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 
19
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 
20
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 
21
 *  See the License for the specific provisions governing your rights and
 
22
 *  obligations concerning the Software.
 
23
 *
 
24
 *   The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 
25
 *
 
26
 *   Copyright: 2001 by Sun Microsystems, Inc.
 
27
 *
 
28
 *   All Rights Reserved.
 
29
 *
 
30
 ************************************************************************/
 
31
/*___INFO__MARK_END__*/
 
32
package com.sun.grid.jgdi.configuration.xml;
 
33
 
 
34
import com.sun.grid.jgdi.configuration.GEObject;
 
35
import com.sun.grid.jgdi.configuration.Util;
 
36
import com.sun.grid.jgdi.configuration.reflect.ClassDescriptor;
 
37
import com.sun.grid.jgdi.configuration.reflect.ListPropertyDescriptor;
 
38
import com.sun.grid.jgdi.configuration.reflect.MapListPropertyDescriptor;
 
39
import com.sun.grid.jgdi.configuration.reflect.MapPropertyDescriptor;
 
40
import com.sun.grid.jgdi.configuration.reflect.PropertyDescriptor;
 
41
import com.sun.grid.jgdi.configuration.reflect.SimplePropertyDescriptor;
 
42
import java.io.File;
 
43
import java.io.IOException;
 
44
import java.io.InputStream;
 
45
import java.io.OutputStream;
 
46
import java.io.Reader;
 
47
import java.io.Writer;
 
48
import java.util.Iterator;
 
49
import java.util.Map;
 
50
import java.util.Set;
 
51
import java.util.Stack;
 
52
import java.util.logging.Level;
 
53
import java.util.logging.Logger;
 
54
import javax.xml.parsers.ParserConfigurationException;
 
55
import javax.xml.parsers.SAXParser;
 
56
import javax.xml.parsers.SAXParserFactory;
 
57
import org.xml.sax.InputSource;
 
58
import org.xml.sax.Locator;
 
59
import org.xml.sax.SAXException;
 
60
import org.xml.sax.SAXParseException;
 
61
import org.xml.sax.helpers.DefaultHandler;
 
62
 
 
63
 
 
64
/**
 
65
 * This class implements the serialisation/deserialion of cull object
 
66
 * int xml.
 
67
 * @jgdi.todo   alpha ??
 
68
 *         <p>Implement missing primitive handlers</p>
 
69
 */
 
70
public class XMLUtil {
 
71
    
 
72
    private static Logger logger = Logger.getLogger(XMLUtil.class.getName());
 
73
    
 
74
    public static final String HEADER = "<?xml version='1.0' encoding='UTF-8'?>";
 
75
    
 
76
    private static final String NONE = "NONE";
 
77
    
 
78
    
 
79
    public static class Context {
 
80
        
 
81
        private final IndentedPrintWriter p;
 
82
        private boolean hideReadOnly;
 
83
        private boolean hideConfigurable;
 
84
        private boolean hideBrowseable;
 
85
        
 
86
        public Context(IndentedPrintWriter p) {
 
87
            this.p = p;
 
88
            setHideReadOnly(true);
 
89
            setHideConfigurable(false);
 
90
            setHideBrowseable(false);
 
91
        }
 
92
        
 
93
        public Context(Writer wr)  {
 
94
            this(new IndentedPrintWriter(wr));
 
95
        }
 
96
        
 
97
        public Context(OutputStream out) {
 
98
            this(new IndentedPrintWriter(out));
 
99
        }
 
100
 
 
101
        public Context(File file) throws IOException {
 
102
            this(new IndentedPrintWriter(file));
 
103
        }
 
104
        
 
105
        public boolean include(PropertyDescriptor pd) {
 
106
            if(pd.isReadOnly() && hideReadOnly) {
 
107
                return false;
 
108
            } else if (pd.isConfigurable() && hideConfigurable) {
 
109
                return false;
 
110
            } else if (pd.isBrowsable() && hideBrowseable) {
 
111
                return false;
 
112
            }
 
113
            return true;
 
114
        }
 
115
 
 
116
        public boolean isHideReadOnly() {
 
117
            return hideReadOnly;
 
118
        }
 
119
 
 
120
        public void setHideReadOnly(boolean hideReadOnly) {
 
121
            this.hideReadOnly = hideReadOnly;
 
122
        }
 
123
 
 
124
        public boolean isHideConfigurable() {
 
125
            return hideConfigurable;
 
126
        }
 
127
 
 
128
        public void setHideConfigurable(boolean hideConfigurable) {
 
129
            this.hideConfigurable = hideConfigurable;
 
130
        }
 
131
 
 
132
        public boolean isHideBrowseable() {
 
133
            return hideBrowseable;
 
134
        }
 
135
 
 
136
        public void setHideBrowseable(boolean hideBrowseable) {
 
137
            this.hideBrowseable = hideBrowseable;
 
138
        }
 
139
        
 
140
    }
 
141
    
 
142
    public static boolean write(GEObject obj, Context ctx) {
 
143
        ctx.p.println(HEADER);
 
144
        write(obj, obj.getClass(), ctx);
 
145
        ctx.p.close();
 
146
        return ctx.p.checkError();
 
147
    }
 
148
    
 
149
    public static boolean write(GEObject obj, Writer wr) throws IOException {
 
150
        Context ctx = new Context(wr);
 
151
        return write(obj, ctx);
 
152
    }
 
153
 
 
154
    public static boolean write(GEObject obj, OutputStream out) throws IOException {
 
155
        Context ctx = new Context(out);
 
156
        return write(obj, ctx);
 
157
    }
 
158
    
 
159
    public static boolean write(GEObject obj, File file) throws IOException {
 
160
        Context ctx = new Context(file);
 
161
        return write(obj, ctx);
 
162
    }
 
163
    
 
164
    private static void write(GEObject obj, Class clazz, Context ctx) {
 
165
        
 
166
        ClassDescriptor cd = Util.getDescriptor(clazz);
 
167
        ctx.p.print('<');
 
168
        ctx.p.print(cd.getCullName());
 
169
        ctx.p.print('>');
 
170
        if (obj == null) {
 
171
            ctx.p.print(NONE);
 
172
        } else {
 
173
            ctx.p.println();
 
174
            ctx.p.indent();
 
175
            for(int i = 0; i < cd.getPropertyCount(); i++) {
 
176
                PropertyDescriptor pd = cd.getProperty(i);
 
177
                
 
178
                if (!ctx.include(pd)) {
 
179
                    continue;
 
180
                }
 
181
                if (pd instanceof SimplePropertyDescriptor) {
 
182
                    write(obj, (SimplePropertyDescriptor)pd, ctx);
 
183
                } else if (pd instanceof ListPropertyDescriptor) {
 
184
                    write(obj, (ListPropertyDescriptor)pd, ctx);
 
185
                } else if (pd instanceof MapPropertyDescriptor) {
 
186
                    write(obj, (MapPropertyDescriptor)pd, ctx);
 
187
                } else if (pd instanceof MapListPropertyDescriptor) {
 
188
                    write(obj, (MapListPropertyDescriptor)pd, ctx);
 
189
                } else {
 
190
                    throw new IllegalStateException("Unknown property type " + pd.getClass());
 
191
                }
 
192
                
 
193
            }
 
194
            ctx.p.deindent();
 
195
        }
 
196
        ctx.p.print("</");
 
197
        ctx.p.print(cd.getCullName());
 
198
        ctx.p.println('>');
 
199
        
 
200
    }
 
201
    
 
202
    private static void write(GEObject obj, SimplePropertyDescriptor pd, Context ctx) {
 
203
        
 
204
        Object value = pd.getValue(obj);
 
205
        if (value != null) {
 
206
            ctx.p.print('<');
 
207
            ctx.p.print(pd.getPropertyName());
 
208
            ctx.p.print('>');
 
209
            if (GEObject.class.isAssignableFrom(pd.getPropertyType())) {
 
210
                if (value == null) {
 
211
                    write((GEObject)value, pd.getPropertyType(), ctx);
 
212
                } else {
 
213
                    write((GEObject)value, value.getClass(), ctx);
 
214
                }
 
215
            } else {
 
216
                ctx.p.print(quoteCharacters(value.toString()));
 
217
            }
 
218
            ctx.p.print("</");
 
219
            ctx.p.print(pd.getPropertyName());
 
220
            ctx.p.println('>');
 
221
        }
 
222
    }
 
223
    
 
224
    private static void write(GEObject obj, ListPropertyDescriptor pd, Context ctx) {
 
225
        
 
226
        int count = pd.getCount(obj);
 
227
        
 
228
        ctx.p.print('<');
 
229
        ctx.p.print(pd.getPropertyName());
 
230
        ctx.p.print('>');
 
231
        if (count == 0) {
 
232
            ctx.p.print(NONE);
 
233
        } else {
 
234
            ctx.p.println();
 
235
            ctx.p.indent();
 
236
            for(int i = 0; i < count; i++) {
 
237
                Object value = pd.get(obj,i);
 
238
                if (GEObject.class.isAssignableFrom(pd.getPropertyType())) {
 
239
                    if (value == null) {
 
240
                        write((GEObject)value, pd.getPropertyType(), ctx);
 
241
                    } else {
 
242
                        write((GEObject)value, value.getClass(), ctx);
 
243
                    }
 
244
                } else {
 
245
                    writePrimitive(value, pd.getPropertyType(), ctx);
 
246
                }
 
247
            }
 
248
            ctx.p.deindent();
 
249
        }
 
250
        ctx.p.print("</");
 
251
        ctx.p.print(pd.getPropertyName());
 
252
        ctx.p.println('>');
 
253
    }
 
254
    
 
255
    private static void write(GEObject obj, MapPropertyDescriptor pd, Context ctx) {
 
256
        
 
257
        Set keys = pd.getKeys(obj);
 
258
        
 
259
        Iterator keyIter = keys.iterator();
 
260
        while(keyIter.hasNext()) {
 
261
            Object key = keyIter.next();
 
262
            Object value = pd.get(obj,key);
 
263
            ctx.p.print('<');
 
264
            ctx.p.print(pd.getPropertyName());
 
265
            ctx.p.print(" key='");
 
266
            ctx.p.print(quoteCharacters(key.toString()));
 
267
            ctx.p.print("'>");
 
268
            if (GEObject.class.isAssignableFrom(pd.getPropertyType())) {
 
269
                ctx.p.println();
 
270
                ctx.p.indent();
 
271
                if (value == null) {
 
272
                    write((GEObject)value, pd.getPropertyType(), ctx);
 
273
                } else {
 
274
                    write((GEObject)value, value.getClass(), ctx);
 
275
                }
 
276
                ctx.p.deindent();
 
277
            } else {
 
278
                if (value == null) {
 
279
                    ctx.p.print(NONE);
 
280
                } else {
 
281
                    ctx.p.print(quoteCharacters(value.toString()));
 
282
                }
 
283
            }
 
284
            ctx.p.print("</");
 
285
            ctx.p.print(pd.getPropertyName());
 
286
            ctx.p.println('>');
 
287
        }
 
288
    }
 
289
    
 
290
    public static final String STRING_TAG = "string";
 
291
    public static final String BOOLEAN_TAG = "boolean";
 
292
    public static final String INT_TAG = "int";
 
293
    public static final String SHORT_TAG = "short";
 
294
    public static final String LONG_TAG = "long";
 
295
    public static final String DOUBLE_TAG = "double";
 
296
    public static final String FLOAT_TAG = "float";
 
297
    
 
298
    private static void writePrimitive(Object value, Class clazz, Context ctx) {
 
299
        
 
300
        String tag = null;
 
301
        if (String.class.isAssignableFrom(clazz)) {
 
302
            tag = STRING_TAG;
 
303
        } else if (Boolean.TYPE.isAssignableFrom(clazz) ||
 
304
                Boolean.class.isAssignableFrom(clazz)) {
 
305
            tag = BOOLEAN_TAG;
 
306
        } else if (Integer.TYPE.isAssignableFrom(clazz) ||
 
307
                Integer.class.isAssignableFrom(clazz)) {
 
308
            tag = INT_TAG;
 
309
        } else if (Short.TYPE.isAssignableFrom(clazz) ||
 
310
                Short.class.isAssignableFrom(clazz)) {
 
311
            tag = SHORT_TAG;
 
312
        } else if (Long.TYPE.isAssignableFrom(clazz) ||
 
313
                Long.class.isAssignableFrom(clazz)) {
 
314
            tag = LONG_TAG;
 
315
        } else if (Double.TYPE.isAssignableFrom(clazz) ||
 
316
                Double.class.isAssignableFrom(clazz)) {
 
317
            tag = DOUBLE_TAG;
 
318
        } else if (Float.TYPE.isAssignableFrom(clazz) ||
 
319
                Float.class.isAssignableFrom(clazz)) {
 
320
            tag = FLOAT_TAG;
 
321
        } else {
 
322
            throw new IllegalArgumentException("Unknown primitive type " + clazz.getName());
 
323
        }
 
324
        ctx.p.print("<");
 
325
        ctx.p.print(tag);
 
326
        ctx.p.print('>');
 
327
        if (value == null) {
 
328
            if (String.class.isAssignableFrom(clazz)) {
 
329
                ctx.p.print(NONE);
 
330
            } else {
 
331
                throw new IllegalArgumentException("Don't know howto handle null value for type " + clazz.getName());
 
332
            }
 
333
        } else {
 
334
            ctx.p.print(quoteCharacters(value.toString()));
 
335
        }
 
336
        ctx.p.print("</");
 
337
        ctx.p.print(tag);
 
338
        ctx.p.println('>');
 
339
        
 
340
    }
 
341
    
 
342
    private static void write(GEObject obj, MapListPropertyDescriptor pd, Context ctx) {
 
343
        
 
344
        Set keys = pd.getKeys(obj);
 
345
        
 
346
        Iterator keyIter = keys.iterator();
 
347
        while(keyIter.hasNext()) {
 
348
            Object key = keyIter.next();
 
349
            ctx.p.print('<');
 
350
            ctx.p.print(pd.getPropertyName());
 
351
            ctx.p.print(" key='");
 
352
            ctx.p.print(quoteCharacters(key.toString()));
 
353
            ctx.p.print("'>");
 
354
            int count = pd.getCount(obj, key);
 
355
            if (count == 0) {
 
356
                ctx.p.println();
 
357
                ctx.p.indent();
 
358
                if (GEObject.class.isAssignableFrom(pd.getPropertyType())) {
 
359
                    write((GEObject)null, pd.getPropertyType(), ctx);
 
360
                } else {
 
361
                    writePrimitive(null, pd.getPropertyType(), ctx);
 
362
                }
 
363
                ctx.p.deindent();
 
364
            } else {
 
365
                ctx.p.println();
 
366
                ctx.p.indent();
 
367
                for(int i = 0; i < count; i++) {
 
368
                    Object value = pd.get(obj, key, i);
 
369
                    if (GEObject.class.isAssignableFrom(pd.getPropertyType())) {
 
370
                        if (value == null) {
 
371
                            write((GEObject)value, pd.getPropertyType(), ctx);
 
372
                        } else {
 
373
                            write((GEObject)value, value.getClass(), ctx);
 
374
                        }
 
375
                    } else {
 
376
                        writePrimitive(value, pd.getPropertyType(), ctx);
 
377
                    }
 
378
                }
 
379
                ctx.p.deindent();
 
380
            }
 
381
            ctx.p.print("</");
 
382
            ctx.p.print(pd.getPropertyName());
 
383
            ctx.p.println('>');
 
384
        }
 
385
    }
 
386
    
 
387
    private static String quoteCharacters(String s) {
 
388
        StringBuilder result = null;
 
389
        for(int i = 0, max = s.length(), delta = 0; i < max; i++) {
 
390
            char c = s.charAt(i);
 
391
            String replacement = null;
 
392
            
 
393
            if (c == '&') {
 
394
                replacement = "&amp;";
 
395
            } else if (c == '<') {
 
396
                replacement = "&lt;";
 
397
            } else if (c == '\r') {
 
398
                replacement = "&#13;";
 
399
            } else if (c == '>') {
 
400
                replacement = "&gt;";
 
401
            } else if (c == '"') {
 
402
                replacement = "&quot;";
 
403
            } else if (c == '\'') {
 
404
                replacement = "&apos;";
 
405
            }
 
406
            
 
407
            if (replacement != null) {
 
408
                if (result == null) {
 
409
                    result = new StringBuilder(s);
 
410
                }
 
411
                result.replace(i + delta, i + delta + 1, replacement);
 
412
                delta += (replacement.length() - 1);
 
413
            }
 
414
        }
 
415
        if (result == null) {
 
416
            return s;
 
417
        }
 
418
        return result.toString();
 
419
    }
 
420
    
 
421
    
 
422
    /**
 
423
     * Read a XML definition of a gridengine object from an <code>InputStream</code>.
 
424
     *
 
425
     * @param in   the InputStream
 
426
     * @param properties All ${key} expressions in the xml file will be replaced be
 
427
     *                   the corresponding value from the properties
 
428
     * @throws java.io.IOException   on any I/O Error
 
429
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
430
     * @throws org.xml.sax.SAXException on any parse error
 
431
     * @return the gridengine object
 
432
     */
 
433
    public static Object read(InputStream in, Map properties)  throws IOException, ParserConfigurationException, SAXException {
 
434
        // Use an instance of ourselves as the SAX event handler
 
435
        RootHandler handler = new RootHandler(properties);
 
436
        
 
437
        // Use the default (non-validating) parser
 
438
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
439
        
 
440
        // Parse the input
 
441
        SAXParser saxParser = factory.newSAXParser();
 
442
        
 
443
        saxParser.parse(in, handler);
 
444
        
 
445
        return handler.getObject();
 
446
    }
 
447
    
 
448
    /**
 
449
     * Read a XML definition of a gridengine object from an <code>InputStream</code>.
 
450
     *
 
451
     * @param in   the InputStream
 
452
     * @throws java.io.IOException   on any I/O Error
 
453
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
454
     * @throws org.xml.sax.SAXException on any parse error
 
455
     * @return the gridengine object
 
456
     */
 
457
    public static Object read(InputStream in)  throws IOException, ParserConfigurationException, SAXException {
 
458
        return read(in, null);
 
459
    }
 
460
    
 
461
    /**
 
462
     * Read a XML definition of a gridengine object from a <code>File</code>.
 
463
     *
 
464
     * @param file   the file
 
465
     * @param properties All ${key} expressions in the xml file will be replaced be
 
466
     *                   the corresponding value from the properties
 
467
     * @throws java.io.IOException   on any I/O Error
 
468
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
469
     * @throws org.xml.sax.SAXException on any parse error
 
470
     * @return the gridengine object
 
471
     */
 
472
    public static Object read(File file, Map properties) throws IOException, ParserConfigurationException, SAXException {
 
473
        // Use an instance of ourselves as the SAX event handler
 
474
        RootHandler handler = new RootHandler(properties);
 
475
        
 
476
        // Use the default (non-validating) parser
 
477
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
478
        
 
479
        // Parse the input
 
480
        SAXParser saxParser = factory.newSAXParser();
 
481
        
 
482
        saxParser.parse(file, handler);
 
483
        
 
484
        return handler.getObject();
 
485
    }
 
486
    
 
487
    /**
 
488
     * Read a XML definition of a gridengine object from a <code>File</code>.
 
489
     *
 
490
     * @param file   the file
 
491
     * @throws java.io.IOException   on any I/O Error
 
492
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
493
     * @throws org.xml.sax.SAXException on any parse error
 
494
     * @return the gridengine object
 
495
     */
 
496
    public static Object read(File file) throws IOException, ParserConfigurationException, SAXException {
 
497
        return read(file, null);
 
498
    }
 
499
    
 
500
    /**
 
501
     * Read a XML definition of a gridengine object from a <code>Reader</code>.
 
502
     *
 
503
     * @param  rd  the reader
 
504
     * @throws java.io.IOException   on any I/O Error
 
505
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
506
     * @throws org.xml.sax.SAXException on any parse error
 
507
     * @return the gridengine object
 
508
     */
 
509
    public static Object read(Reader rd, Map properties) throws IOException, ParserConfigurationException, SAXException {
 
510
        
 
511
        // Use an instance of ourselves as the SAX event handler
 
512
        RootHandler handler = new RootHandler(properties);
 
513
        
 
514
        // Use the default (non-validating) parser
 
515
        SAXParserFactory factory = SAXParserFactory.newInstance();
 
516
        
 
517
        // Parse the input
 
518
        SAXParser saxParser = factory.newSAXParser();
 
519
        InputSource source = new InputSource(rd);
 
520
        saxParser.parse(source, handler);
 
521
        
 
522
        return handler.getObject();
 
523
    }
 
524
    
 
525
    /**
 
526
     * Read a XML definition of a gridengine object from a <code>Reader</code>.
 
527
     *
 
528
     * @param  rd  the reader
 
529
     * @throws java.io.IOException   on any I/O Error
 
530
     * @throws javax.xml.parsers.ParserConfigurationException if a SAX parser has an invalid configuration
 
531
     * @throws org.xml.sax.SAXException on any parse error
 
532
     * @return the gridengine object
 
533
     */
 
534
    public static Object read(Reader rd) throws IOException, ParserConfigurationException, SAXException {
 
535
        return read(rd, null);
 
536
    }
 
537
    
 
538
    
 
539
    static class RootHandler extends DefaultHandler {
 
540
        
 
541
        private Map properties;
 
542
        
 
543
        private Stack stack = new Stack();
 
544
        
 
545
        private Object rootObject;
 
546
        
 
547
        private Locator locator;
 
548
        
 
549
        public RootHandler() {
 
550
            this(null);
 
551
        }
 
552
        
 
553
        public RootHandler(Map properties) {
 
554
            this.properties = properties;
 
555
        }
 
556
        
 
557
        public Object getObject() {
 
558
            return rootObject;
 
559
        }
 
560
        
 
561
        public void setDocumentLocator(Locator locator) {
 
562
            this.locator = locator;
 
563
        }
 
564
        
 
565
        public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attributes) throws org.xml.sax.SAXException {
 
566
            
 
567
            if (logger.isLoggable(Level.FINEST)) {
 
568
                logger.finest("startElement: uri = " + uri + ", localName = " + localName +
 
569
                        " qName = " + qName);
 
570
            }
 
571
            if (stack.isEmpty()) {
 
572
                GEObjectHandler handler = new GEObjectHandler(qName);
 
573
                rootObject = handler.getObject();
 
574
                stack.push(handler);
 
575
            } else {
 
576
                CullHandler handler = (CullHandler)stack.peek();
 
577
                
 
578
                handler = handler.getHandler(qName, attributes);
 
579
                stack.push(handler);
 
580
            }
 
581
        }
 
582
        
 
583
        public void endElement(String uri, String localName, String qName) throws SAXException {
 
584
            
 
585
            if (logger.isLoggable(Level.FINEST)) {
 
586
                logger.finest("endElement: uri = " + uri + ", localName = " + localName +
 
587
                        " qName = " + qName);
 
588
            }
 
589
            CullHandler handler = (CullHandler)stack.pop();
 
590
            handler.endElement(uri, localName, qName);
 
591
        }
 
592
        
 
593
        public void characters(char[] ch, int start, int length) throws org.xml.sax.SAXException {
 
594
            
 
595
            if (logger.isLoggable(Level.FINEST)) {
 
596
                logger.finest("characters: '" + new String(ch, start, length) + "'");
 
597
            }
 
598
            
 
599
            if (properties != null) {
 
600
                ch = resolveResources(ch, start, length);
 
601
                start = 0;
 
602
                length = ch.length;
 
603
            }
 
604
            CullHandler handler = (CullHandler)stack.peek();
 
605
            handler.characters(ch, start, length);
 
606
        }
 
607
        
 
608
        char[] resolveResources(char[] ch, int start, int length) throws SAXException {
 
609
            int end = start + length;
 
610
            int i = start;
 
611
            StringBuilder ret = new StringBuilder();
 
612
            
 
613
            while(i < end) {
 
614
                if (ch[i] == '$') {
 
615
                    i++;
 
616
                    if (i>=end) {
 
617
                        ret.append('$');
 
618
                        break;
 
619
                    }
 
620
                    if (ch[i] == '{') {
 
621
                        // we found the beginning of a property
 
622
                        i++;
 
623
                        if (i>=end) {
 
624
                            throw new SAXException("Unclosed property in " + new String(ch, start, length));
 
625
                        }
 
626
                        int startIndex = i;
 
627
                        int endIndex = -1;
 
628
                        while(i< end) {
 
629
                            if (ch[i] == '}') {
 
630
                                endIndex = i;
 
631
                                break;
 
632
                            }
 
633
                            i++;
 
634
                        }
 
635
                        if (endIndex < 0) {
 
636
                            throw new SAXException("Unclosed property in " + new String(ch, start, length));
 
637
                        }
 
638
                        String property = new String(ch, startIndex, endIndex - startIndex);
 
639
                        
 
640
                        Object value = properties.get(property);
 
641
                        
 
642
                        logger.fine("Replace property " + property + " with value " + value);
 
643
                        if (value != null) {
 
644
                            ret.append(value);
 
645
                        }
 
646
                    } else {
 
647
                        // A single $ sign
 
648
                        ret.append('$');
 
649
                        ret.append(ch[i]);
 
650
                    }
 
651
                } else {
 
652
                    ret.append(ch[i]);
 
653
                }
 
654
                i++;
 
655
            }
 
656
            return ret.toString().toCharArray();
 
657
        }
 
658
        
 
659
        abstract class CullHandler extends DefaultHandler {
 
660
            
 
661
            protected CullHandler parent;
 
662
            
 
663
            public CullHandler(CullHandler parent) {
 
664
                this.parent = parent;
 
665
            }
 
666
            
 
667
            public CullHandler getParent() {
 
668
                return parent;
 
669
            }
 
670
            
 
671
            public abstract CullHandler getHandler(String name, org.xml.sax.Attributes attributes) throws SAXException;
 
672
        }
 
673
        
 
674
        abstract class AbstractObjectHandler extends CullHandler {
 
675
            
 
676
            private String name;
 
677
            
 
678
            public AbstractObjectHandler(CullPropertyHandler parent, String name) {
 
679
                super(parent);
 
680
                this.name = name;
 
681
            }
 
682
            
 
683
            public String getName() {
 
684
                return name;
 
685
            }
 
686
            
 
687
            public abstract Object getObject();
 
688
            
 
689
            public void endElement(String uri, String localName, String qName) throws SAXException {
 
690
                if (parent != null) {
 
691
                    ((CullPropertyHandler)parent).addObject(getObject());
 
692
                }
 
693
            }
 
694
            
 
695
        }
 
696
        
 
697
        class GEObjectHandler extends AbstractObjectHandler {
 
698
            
 
699
            private ClassDescriptor cd;
 
700
            private Object obj;
 
701
            
 
702
            public GEObjectHandler(String name)  throws SAXException {
 
703
                this(null, name);
 
704
            }
 
705
            
 
706
            public Object getObject() {
 
707
                return obj;
 
708
            }
 
709
            
 
710
            public GEObjectHandler(CullPropertyHandler parent, String name)  throws SAXException {
 
711
                super(parent, name);
 
712
                try {
 
713
                    cd = Util.getDescriptorForCullType(name);
 
714
                } catch(IllegalArgumentException ilae) {
 
715
                    throw new SAXParseException("No descriptor for cull type " + name + " found", locator, ilae);
 
716
                }
 
717
                obj = cd.newInstance();
 
718
            }
 
719
            
 
720
            public CullHandler getHandler(String name, org.xml.sax.Attributes attributes) throws SAXException {
 
721
                PropertyDescriptor pd = cd.getProperty(name);
 
722
                if (pd == null) {
 
723
                    throw new SAXParseException("cull type " + cd.getCullName() + " has no property " + name, locator);
 
724
                } if (pd instanceof SimplePropertyDescriptor) {
 
725
                    if (pd.getPropertyType().isPrimitive() || pd.getPropertyType().equals(String.class)) {
 
726
                        return new SimplePropertyHandler(this, (SimplePropertyDescriptor)pd);
 
727
                    } else {
 
728
                        return new ObjectPropertyHandler(this, (SimplePropertyDescriptor)pd);
 
729
                    }
 
730
                } else if (pd instanceof ListPropertyDescriptor) {
 
731
                    return new ListPropertyHandler(this, (ListPropertyDescriptor)pd);
 
732
                } else if (pd instanceof MapPropertyDescriptor) {
 
733
                    return new MapPropertyHandler(this, (MapPropertyDescriptor)pd, attributes);
 
734
                } else if (pd instanceof MapListPropertyDescriptor) {
 
735
                    return new MapListPropertyHandler(this, (MapListPropertyDescriptor)pd, attributes);
 
736
                } else {
 
737
                    throw new SAXParseException("Unknown property type " + pd.getClass(), locator);
 
738
                }
 
739
            }
 
740
            
 
741
            private StringBuilder value;
 
742
            
 
743
            public void characters(char[] ch, int start, int length) throws SAXException {
 
744
                if (length > 0) {
 
745
                    if (value == null) {
 
746
                        value = new StringBuilder();
 
747
                    }
 
748
                    value.append(ch,start,length);
 
749
                }
 
750
            }
 
751
            
 
752
            public void endElement(String uri, String localName, String qName) throws SAXException {
 
753
                if (value != null) {
 
754
                    String str = value.toString().trim();
 
755
                    if (str.length()>0) {
 
756
                        if (NONE.equalsIgnoreCase(str)) {
 
757
                            if (parent instanceof MapListPropertyHandler) {
 
758
                                ((MapListPropertyHandler)parent).addEmptyObject();
 
759
                            } else if (parent instanceof ListPropertyHandler) {
 
760
                                // empty list and null has the same meaning
 
761
                            } else {
 
762
                                throw new SAXException("object can only have content if parent is a map list or a list (2)");
 
763
                            }
 
764
                        } else {
 
765
                            super.endElement(uri, localName, qName);
 
766
                        }
 
767
                    } else {
 
768
                        super.endElement(uri, localName, qName);
 
769
                    }
 
770
                }
 
771
            }
 
772
        }
 
773
        
 
774
        class StringHandler extends AbstractObjectHandler {
 
775
            
 
776
            private StringBuilder buffer;
 
777
            
 
778
            public StringHandler(CullPropertyHandler parent, String name) {
 
779
                super(parent, name);
 
780
            }
 
781
            
 
782
            public CullHandler getHandler(String name, org.xml.sax.Attributes attributes) throws SAXException {
 
783
                throw new SAXException("String handler " + getName() + " does not support sub element " + name);
 
784
            }
 
785
            
 
786
            public void characters(char[] ch, int start, int length) throws SAXException {
 
787
                if (buffer == null) {
 
788
                    buffer = new StringBuilder();
 
789
                }
 
790
                buffer.append(ch,start, length);
 
791
            }
 
792
            
 
793
            public void endElement(String uri, String localName, String qName) throws SAXException {
 
794
                if (buffer == null) {
 
795
                    throw new SAXException("A string tag must not be empty");
 
796
                } else {
 
797
                    super.endElement(uri, localName, qName);
 
798
                }
 
799
            }
 
800
            
 
801
            public Object getObject() {
 
802
                if (buffer != null) {
 
803
                    String ret = buffer.toString();
 
804
                    if (NONE.equalsIgnoreCase(ret)) {
 
805
                        return null;
 
806
                    } else {
 
807
                        return ret;
 
808
                    }
 
809
                } else {
 
810
                    throw new IllegalStateException("A string tag must not be empty");
 
811
                }
 
812
            }
 
813
        }
 
814
        
 
815
        class IntHandler extends StringHandler {
 
816
            public IntHandler(CullPropertyHandler parent, String name) {
 
817
                super(parent, name);
 
818
            }
 
819
            
 
820
            public Object getObject() {
 
821
                return new Integer((String)super.getObject());
 
822
            }
 
823
        }
 
824
        
 
825
        class LongHandler extends StringHandler {
 
826
            public LongHandler(CullPropertyHandler parent, String name) {
 
827
                super(parent, name);
 
828
            }
 
829
            
 
830
            public Object getObject() {
 
831
                return new Long((String)super.getObject());
 
832
            }
 
833
        }
 
834
        
 
835
        class ShortHandler extends StringHandler {
 
836
            public ShortHandler(CullPropertyHandler parent, String name) {
 
837
                super(parent, name);
 
838
            }
 
839
            
 
840
            public Object getObject() {
 
841
                return new Short((String)super.getObject());
 
842
            }
 
843
        }
 
844
        
 
845
        class DoubleHandler extends StringHandler {
 
846
            public DoubleHandler(CullPropertyHandler parent, String name) {
 
847
                super(parent, name);
 
848
            }
 
849
            
 
850
            public Object getObject() {
 
851
                return new Double((String)super.getObject());
 
852
            }
 
853
        }
 
854
        
 
855
        class FloatHandler extends StringHandler {
 
856
            public FloatHandler(CullPropertyHandler parent, String name) {
 
857
                super(parent, name);
 
858
            }
 
859
            
 
860
            public Object getObject() {
 
861
                return new Float((String)super.getObject());
 
862
            }
 
863
        }
 
864
        
 
865
        class BooleanHandler extends StringHandler {
 
866
            public BooleanHandler(CullPropertyHandler parent, String name) {
 
867
                super(parent, name);
 
868
            }
 
869
            
 
870
            public Object getObject() {
 
871
                return new Boolean((String)super.getObject());
 
872
            }
 
873
        }
 
874
        
 
875
        
 
876
        abstract class CullPropertyHandler extends CullHandler {
 
877
            
 
878
            
 
879
            public CullPropertyHandler(GEObjectHandler parent) {
 
880
                super(parent);
 
881
                if (parent == null) {
 
882
                    throw new NullPointerException("parent is null");
 
883
                }
 
884
            }
 
885
            
 
886
            public abstract void addObject(Object obj) throws SAXException;
 
887
            
 
888
            public CullHandler getHandler(String name, org.xml.sax.Attributes attributes) throws SAXException {
 
889
                if (STRING_TAG.equals(name)) {
 
890
                    return new StringHandler(this, name);
 
891
                } else if (DOUBLE_TAG.equals(name)) {
 
892
                    return new DoubleHandler(this, name);
 
893
                } else if (BOOLEAN_TAG.equals(name)) {
 
894
                    return new BooleanHandler(this, name);
 
895
                } else if (INT_TAG.equals(name)) {
 
896
                    return new IntHandler(this, name);
 
897
                } else if (LONG_TAG.equals(name)) {
 
898
                    return new LongHandler(this, name);
 
899
                } else if (SHORT_TAG.equals(name)) {
 
900
                    return new ShortHandler(this,name);
 
901
                } else if (FLOAT_TAG.equals(name)) {
 
902
                    return new FloatHandler(this, name);
 
903
                }
 
904
                return new GEObjectHandler(this, name);
 
905
            }
 
906
            
 
907
        }
 
908
        
 
909
        class SimplePropertyHandler extends CullPropertyHandler {
 
910
            private SimplePropertyDescriptor pd;
 
911
            private StringBuilder value;
 
912
            
 
913
            public SimplePropertyHandler(GEObjectHandler parent, SimplePropertyDescriptor pd) {
 
914
                super(parent);
 
915
                if (pd == null) {
 
916
                    throw new NullPointerException("pd is null");
 
917
                }
 
918
                this.pd = pd;
 
919
            }
 
920
            
 
921
            public void addObject(Object obj) throws SAXException {
 
922
                if (!pd.isReadOnly()) {
 
923
                    if (((GEObjectHandler)parent).getObject() == null) {
 
924
                        throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has no value");
 
925
                    }
 
926
                    pd.setValue(((GEObjectHandler)parent).getObject(), obj);
 
927
                }
 
928
            }
 
929
            
 
930
            public void characters(char[] ch, int start, int length) throws SAXException {
 
931
                if (value == null) {
 
932
                    value = new StringBuilder();
 
933
                }
 
934
                value.append(ch,start,length);
 
935
            }
 
936
            
 
937
            public void endElement(String uri, String localName, String qName) throws SAXException {
 
938
                
 
939
                if (value != null) {
 
940
                    // We have a simple element
 
941
                    String str = value.toString();
 
942
                    addObject(parse(str, pd));
 
943
                }
 
944
            }
 
945
        }
 
946
        
 
947
        class ObjectPropertyHandler extends CullPropertyHandler {
 
948
            private SimplePropertyDescriptor pd;
 
949
            
 
950
            public ObjectPropertyHandler(GEObjectHandler parent, SimplePropertyDescriptor pd) {
 
951
                super(parent);
 
952
                this.pd = pd;
 
953
            }
 
954
            
 
955
            public void addObject(Object obj) throws SAXException {
 
956
                if (((GEObjectHandler)parent).getObject() == null) {
 
957
                    throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has not object");
 
958
                }
 
959
                pd.setValue(((GEObjectHandler)parent).getObject(), obj);
 
960
            }
 
961
        }
 
962
        
 
963
        class ListPropertyHandler extends CullPropertyHandler {
 
964
            private ListPropertyDescriptor pd;
 
965
            
 
966
            public ListPropertyHandler(GEObjectHandler parent, ListPropertyDescriptor pd) {
 
967
                super(parent);
 
968
                this.pd = pd;
 
969
            }
 
970
            
 
971
            public void addObject(Object obj) throws SAXException {
 
972
                if (((GEObjectHandler)parent).getObject() == null) {
 
973
                    throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has not object");
 
974
                }
 
975
                pd.add(((GEObjectHandler)parent).getObject(), obj);
 
976
            }
 
977
        }
 
978
        
 
979
        class MapPropertyHandler extends CullPropertyHandler {
 
980
            private MapPropertyDescriptor pd;
 
981
            private StringBuilder value;
 
982
            private String key;
 
983
            
 
984
            public MapPropertyHandler(GEObjectHandler parent, MapPropertyDescriptor pd, org.xml.sax.Attributes attributes) {
 
985
                super(parent);
 
986
                this.pd = pd;
 
987
                this.key = attributes.getValue("key");
 
988
            }
 
989
            
 
990
            public CullHandler getHandler(String name, org.xml.sax.Attributes attributes)  throws SAXException {
 
991
                if (!pd.getCullType().equals(name)) {
 
992
                    throw new SAXParseException("This handler can only handle object of type " + pd.getCullType(), locator);
 
993
                }
 
994
                return super.getHandler(name, attributes);
 
995
            }
 
996
            
 
997
            public void addObject(Object obj) throws SAXException {
 
998
                if (((GEObjectHandler)parent).getObject() == null) {
 
999
                    throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has no object");
 
1000
                }
 
1001
                /* AA */
 
1002
                if (obj == null) {
 
1003
                    pd.put(((GEObjectHandler)parent).getObject(), key, "NONE");
 
1004
                } else {
 
1005
                    pd.put(((GEObjectHandler)parent).getObject(), key, obj);
 
1006
                }
 
1007
            }
 
1008
            
 
1009
            public void characters(char[] ch, int start, int length) throws SAXException {
 
1010
                if (value == null) {
 
1011
                    value = new StringBuilder();
 
1012
                }
 
1013
                value.append(ch,start,length);
 
1014
            }
 
1015
            
 
1016
            public void endElement(String uri, String localName, String qName) throws SAXException {
 
1017
                if (value != null) {
 
1018
                    // We have a simple element
 
1019
                    String str = value.toString();
 
1020
                    if (NONE.equalsIgnoreCase(str)) {
 
1021
                        addObject(null);
 
1022
                    } else {
 
1023
                        addObject(parse(value.toString(), pd));
 
1024
                    }
 
1025
                }
 
1026
            }
 
1027
        }
 
1028
        
 
1029
        class MapListPropertyHandler extends CullPropertyHandler {
 
1030
            private MapListPropertyDescriptor pd;
 
1031
            private String key;
 
1032
            private StringBuilder value;
 
1033
            
 
1034
            public MapListPropertyHandler(GEObjectHandler parent, MapListPropertyDescriptor pd, org.xml.sax.Attributes attributes) {
 
1035
                super(parent);
 
1036
                this.pd = pd;
 
1037
                this.key = attributes.getValue("key");
 
1038
            }
 
1039
            
 
1040
            public CullHandler getHandler(String name, org.xml.sax.Attributes attributes)  throws SAXException {
 
1041
                return super.getHandler(name, attributes);
 
1042
            }
 
1043
            
 
1044
            public void addObject(Object obj) throws SAXException {
 
1045
                if (pd == null) {
 
1046
                    throw new NullPointerException("pd is null");
 
1047
                }
 
1048
                if (parent == null) {
 
1049
                    throw new NullPointerException("parent is null");
 
1050
                }
 
1051
                if (((GEObjectHandler)parent).getObject() == null) {
 
1052
                    throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has not object");
 
1053
                }
 
1054
                if (obj != null) {
 
1055
                    pd.add(((GEObjectHandler)parent).getObject(), key, obj);
 
1056
                } else {
 
1057
                    addEmptyObject();
 
1058
                }
 
1059
                
 
1060
            }
 
1061
            
 
1062
            public void addEmptyObject() throws SAXException {
 
1063
                if (pd == null) {
 
1064
                    throw new NullPointerException("pd is null");
 
1065
                }
 
1066
                if (parent == null) {
 
1067
                    throw new NullPointerException("parent is null");
 
1068
                }
 
1069
                if (((GEObjectHandler)parent).getObject() == null) {
 
1070
                    throw new SAXException("parent " + ((GEObjectHandler)parent).getName() + " has no object");
 
1071
                }
 
1072
                pd.addEmpty(((GEObjectHandler)parent).getObject(), key);
 
1073
            }
 
1074
            
 
1075
        }
 
1076
        
 
1077
        
 
1078
        /**
 
1079
         * parse methode for primitive and string elements
 
1080
         * @param value  the value which should be parsed
 
1081
         * @param PropertyDescriptor  descriptor of the property
 
1082
         * @throws org.xml.sax.SAXException the value could not be parsed
 
1083
         * @return the parsed value
 
1084
         */
 
1085
        private Object parse(String value, PropertyDescriptor pd) throws SAXException {
 
1086
            Class clazz = pd.getPropertyType();
 
1087
            if (pd.hasCullWrapper()) {
 
1088
                
 
1089
                ClassDescriptor realClassDescriptor = Util.getDescriptor(pd.getPropertyType());
 
1090
                
 
1091
                Object obj = realClassDescriptor.newInstance();
 
1092
                
 
1093
                PropertyDescriptor rpd = realClassDescriptor.getPropertyByCullFieldName(pd.getCullContentField());
 
1094
                
 
1095
                if (rpd instanceof SimplePropertyDescriptor) {
 
1096
                    ((SimplePropertyDescriptor)rpd).setValue(obj, parse(value, rpd));
 
1097
                    return obj;
 
1098
                } else {
 
1099
                    throw new SAXParseException("Can only handle simple wrapped properties", locator);
 
1100
                }
 
1101
            } else if (Boolean.TYPE.isAssignableFrom(clazz)) {
 
1102
                return new Boolean(value);
 
1103
            } else if (Integer.TYPE.isAssignableFrom(clazz)) {
 
1104
                try {
 
1105
                    return new Integer(value);
 
1106
                } catch(NumberFormatException nfe) {
 
1107
                    throw new SAXParseException("'" + value + "' is not a valid int value", locator, nfe);
 
1108
                }
 
1109
            } else if (Long.TYPE.isAssignableFrom(clazz)) {
 
1110
                try {
 
1111
                    return new Long(value);
 
1112
                } catch(NumberFormatException nfe) {
 
1113
                    throw new SAXParseException("'" + value + "' is not a valid long value", locator, nfe);
 
1114
                }
 
1115
            } else if (Float.TYPE.isAssignableFrom(clazz)) {
 
1116
                try {
 
1117
                    return new Float(value);
 
1118
                } catch(NumberFormatException nfe) {
 
1119
                    throw new SAXParseException("'" + value + "' is not a valid float value", locator, nfe);
 
1120
                }
 
1121
            } else if (Double.TYPE.isAssignableFrom(clazz)) {
 
1122
                try {
 
1123
                    return new Double(value);
 
1124
                } catch(NumberFormatException nfe) {
 
1125
                    throw new SAXParseException("'" + value + "' is not a valid double value", locator, nfe);
 
1126
                }
 
1127
            } else if (String.class.isAssignableFrom(clazz)) {
 
1128
                return value;
 
1129
            } else {
 
1130
                throw new SAXParseException("Can not parse object of type " + clazz, locator);
 
1131
            }
 
1132
        }
 
1133
    }
 
1134
}