KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dom4j > io > SAXEventRecorder


1 /*
2  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3  *
4  * This software is open source.
5  * See the bottom of this file for the licence.
6  */

7
8 package org.dom4j.io;
9
10 import java.io.Externalizable JavaDoc;
11 import java.io.IOException JavaDoc;
12 import java.io.ObjectInput JavaDoc;
13 import java.io.ObjectOutput JavaDoc;
14 import java.util.ArrayList JavaDoc;
15 import java.util.HashMap JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
19
20 import org.dom4j.Namespace;
21 import org.dom4j.QName;
22 import org.xml.sax.Attributes JavaDoc;
23 import org.xml.sax.ContentHandler JavaDoc;
24 import org.xml.sax.DTDHandler JavaDoc;
25 import org.xml.sax.SAXException JavaDoc;
26 import org.xml.sax.ext.DeclHandler JavaDoc;
27 import org.xml.sax.ext.LexicalHandler JavaDoc;
28 import org.xml.sax.helpers.AttributesImpl JavaDoc;
29 import org.xml.sax.helpers.DefaultHandler JavaDoc;
30
31 /**
32  * <p>
33  * Records SAX events such that they may be "replayed" at a later time. Provides
34  * an alternative serialization approach when externalizing a DOM4J document.
35  * Rather than serializing a document as text and re-parsing, the sax events may
36  * be serialized instead.
37  * </p>
38  * Example usage:
39  *
40  * <pre>
41  *
42  *
43  *
44  * SAXEventRecorder recorder = new SAXEventRecorder();
45  * SAXWriter saxWriter = new SAXWriter(recorder, recorder);
46  * saxWriter.write(document);
47  * out.writeObject(recorder);
48  * ...
49  * SAXEventRecorder recorder = (SAXEventRecorder)in.readObject();
50  * SAXContentHandler saxContentHandler = new SAXContentHandler();
51  * recorder.replay(saxContentHandler);
52  * Document document = saxContentHandler.getDocument();
53  *
54  *
55  *
56  * </pre>
57  *
58  * @author Todd Wolff (Bluestem Software)
59  */

60 public class SAXEventRecorder extends DefaultHandler JavaDoc implements LexicalHandler JavaDoc,
61         DeclHandler JavaDoc, DTDHandler JavaDoc, Externalizable JavaDoc {
62     public static final long serialVersionUID = 1;
63
64     private static final byte STRING = 0;
65
66     private static final byte OBJECT = 1;
67
68     private static final byte NULL = 2;
69
70     private List JavaDoc events = new ArrayList JavaDoc();
71
72     private Map JavaDoc prefixMappings = new HashMap JavaDoc();
73
74     private static final String JavaDoc XMLNS = "xmlns";
75
76     private static final String JavaDoc EMPTY_STRING = "";
77
78     public SAXEventRecorder() {
79     }
80
81     public void replay(ContentHandler JavaDoc handler) throws SAXException JavaDoc {
82         SAXEvent saxEvent;
83         Iterator JavaDoc itr = events.iterator();
84
85         while (itr.hasNext()) {
86             saxEvent = (SAXEvent) itr.next();
87
88             switch (saxEvent.event) {
89                 // replay to ContentHandler
90
case SAXEvent.PROCESSING_INSTRUCTION:
91                     handler.processingInstruction((String JavaDoc) saxEvent.getParm(0),
92                             (String JavaDoc) saxEvent.getParm(1));
93
94                     break;
95
96                 case SAXEvent.START_PREFIX_MAPPING:
97                     handler.startPrefixMapping((String JavaDoc) saxEvent.getParm(0),
98                             (String JavaDoc) saxEvent.getParm(1));
99
100                     break;
101
102                 case SAXEvent.END_PREFIX_MAPPING:
103                     handler.endPrefixMapping((String JavaDoc) saxEvent.getParm(0));
104
105                     break;
106
107                 case SAXEvent.START_DOCUMENT:
108                     handler.startDocument();
109
110                     break;
111
112                 case SAXEvent.END_DOCUMENT:
113                     handler.endDocument();
114
115                     break;
116
117                 case SAXEvent.START_ELEMENT:
118
119                     AttributesImpl JavaDoc attributes = new AttributesImpl JavaDoc();
120                     List JavaDoc attParmList = (List JavaDoc) saxEvent.getParm(3);
121
122                     if (attParmList != null) {
123                         Iterator JavaDoc attsItr = attParmList.iterator();
124
125                         while (attsItr.hasNext()) {
126                             String JavaDoc[] attParms = (String JavaDoc[]) attsItr.next();
127                             attributes.addAttribute(attParms[0], attParms[1],
128                                     attParms[2], attParms[3], attParms[4]);
129                         }
130                     }
131
132                     handler.startElement((String JavaDoc) saxEvent.getParm(0),
133                             (String JavaDoc) saxEvent.getParm(1), (String JavaDoc) saxEvent
134                                     .getParm(2), attributes);
135
136                     break;
137
138                 case SAXEvent.END_ELEMENT:
139                     handler.endElement((String JavaDoc) saxEvent.getParm(0),
140                             (String JavaDoc) saxEvent.getParm(1), (String JavaDoc) saxEvent
141                                     .getParm(2));
142
143                     break;
144
145                 case SAXEvent.CHARACTERS:
146
147                     char[] chars = (char[]) saxEvent.getParm(0);
148                     int start = ((Integer JavaDoc) saxEvent.getParm(1)).intValue();
149                     int end = ((Integer JavaDoc) saxEvent.getParm(2)).intValue();
150                     handler.characters(chars, start, end);
151
152                     break;
153
154                 // replay to LexicalHandler
155
case SAXEvent.START_DTD:
156                     ((LexicalHandler JavaDoc) handler).startDTD((String JavaDoc) saxEvent
157                             .getParm(0), (String JavaDoc) saxEvent.getParm(1),
158                             (String JavaDoc) saxEvent.getParm(2));
159
160                     break;
161
162                 case SAXEvent.END_DTD:
163                     ((LexicalHandler JavaDoc) handler).endDTD();
164
165                     break;
166
167                 case SAXEvent.START_ENTITY:
168                     ((LexicalHandler JavaDoc) handler).startEntity((String JavaDoc) saxEvent
169                             .getParm(0));
170
171                     break;
172
173                 case SAXEvent.END_ENTITY:
174                     ((LexicalHandler JavaDoc) handler).endEntity((String JavaDoc) saxEvent
175                             .getParm(0));
176
177                     break;
178
179                 case SAXEvent.START_CDATA:
180                     ((LexicalHandler JavaDoc) handler).startCDATA();
181
182                     break;
183
184                 case SAXEvent.END_CDATA:
185                     ((LexicalHandler JavaDoc) handler).endCDATA();
186
187                     break;
188
189                 case SAXEvent.COMMENT:
190
191                     char[] cchars = (char[]) saxEvent.getParm(0);
192                     int cstart = ((Integer JavaDoc) saxEvent.getParm(1)).intValue();
193                     int cend = ((Integer JavaDoc) saxEvent.getParm(2)).intValue();
194                     ((LexicalHandler JavaDoc) handler).comment(cchars, cstart, cend);
195
196                     break;
197
198                 // replay to DeclHandler
199
case SAXEvent.ELEMENT_DECL:
200                     ((DeclHandler JavaDoc) handler).elementDecl((String JavaDoc) saxEvent
201                             .getParm(0), (String JavaDoc) saxEvent.getParm(1));
202
203                     break;
204
205                 case SAXEvent.ATTRIBUTE_DECL:
206                     ((DeclHandler JavaDoc) handler).attributeDecl((String JavaDoc) saxEvent
207                             .getParm(0), (String JavaDoc) saxEvent.getParm(1),
208                             (String JavaDoc) saxEvent.getParm(2), (String JavaDoc) saxEvent
209                                     .getParm(3), (String JavaDoc) saxEvent.getParm(4));
210
211                     break;
212
213                 case SAXEvent.INTERNAL_ENTITY_DECL:
214                     ((DeclHandler JavaDoc) handler).internalEntityDecl(
215                             (String JavaDoc) saxEvent.getParm(0), (String JavaDoc) saxEvent
216                                     .getParm(1));
217
218                     break;
219
220                 case SAXEvent.EXTERNAL_ENTITY_DECL:
221                     ((DeclHandler JavaDoc) handler).externalEntityDecl(
222                             (String JavaDoc) saxEvent.getParm(0), (String JavaDoc) saxEvent
223                                     .getParm(1), (String JavaDoc) saxEvent.getParm(2));
224
225                     break;
226
227                 default:
228                     throw new SAXException JavaDoc("Unrecognized event: "
229                             + saxEvent.event);
230             }
231         }
232     }
233
234     // ContentHandler interface
235
// -------------------------------------------------------------------------
236
public void processingInstruction(String JavaDoc target, String JavaDoc data)
237             throws SAXException JavaDoc {
238         SAXEvent saxEvent = new SAXEvent(SAXEvent.PROCESSING_INSTRUCTION);
239         saxEvent.addParm(target);
240         saxEvent.addParm(data);
241         events.add(saxEvent);
242     }
243
244     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
245             throws SAXException JavaDoc {
246         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_PREFIX_MAPPING);
247         saxEvent.addParm(prefix);
248         saxEvent.addParm(uri);
249         events.add(saxEvent);
250     }
251
252     public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc {
253         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_PREFIX_MAPPING);
254         saxEvent.addParm(prefix);
255         events.add(saxEvent);
256     }
257
258     public void startDocument() throws SAXException JavaDoc {
259         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_DOCUMENT);
260         events.add(saxEvent);
261     }
262
263     public void endDocument() throws SAXException JavaDoc {
264         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_DOCUMENT);
265         events.add(saxEvent);
266     }
267
268     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName,
269             String JavaDoc qualifiedName, Attributes JavaDoc attributes) throws SAXException JavaDoc {
270         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_ELEMENT);
271         saxEvent.addParm(namespaceURI);
272         saxEvent.addParm(localName);
273         saxEvent.addParm(qualifiedName);
274
275         QName qName = null;
276         if (namespaceURI != null) {
277             qName = new QName(localName, Namespace.get(namespaceURI));
278         } else {
279             qName = new QName(localName);
280         }
281
282         if ((attributes != null) && (attributes.getLength() > 0)) {
283             List JavaDoc attParmList = new ArrayList JavaDoc(attributes.getLength());
284             String JavaDoc[] attParms = null;
285
286             for (int i = 0; i < attributes.getLength(); i++) {
287
288                 String JavaDoc attLocalName = attributes.getLocalName(i);
289
290                 if (attLocalName.startsWith(XMLNS)) {
291
292                     // if SAXWriter is writing a DOMDocument, namespace
293
// decls are treated as attributes. record a start
294
// prefix mapping event
295
String JavaDoc prefix = null;
296                     if (attLocalName.length() > 5) {
297                         prefix = attLocalName.substring(6);
298                     } else {
299                         prefix = EMPTY_STRING;
300                     }
301
302                     SAXEvent prefixEvent = new SAXEvent(
303                             SAXEvent.START_PREFIX_MAPPING);
304                     prefixEvent.addParm(prefix);
305                     prefixEvent.addParm(attributes.getValue(i));
306                     events.add(prefixEvent);
307
308                     // 'register' the prefix so that we can generate
309
// an end prefix mapping event within endElement
310
List JavaDoc prefixes = (List JavaDoc) prefixMappings.get(qName);
311                     if (prefixes == null) {
312                         prefixes = new ArrayList JavaDoc();
313                         prefixMappings.put(qName, prefixes);
314                     }
315                     prefixes.add(prefix);
316
317                 } else {
318
319                     attParms = new String JavaDoc[5];
320                     attParms[0] = attributes.getURI(i);
321                     attParms[1] = attLocalName;
322                     attParms[2] = attributes.getQName(i);
323                     attParms[3] = attributes.getType(i);
324                     attParms[4] = attributes.getValue(i);
325                     attParmList.add(attParms);
326
327                 }
328
329             }
330
331             saxEvent.addParm(attParmList);
332         }
333
334         events.add(saxEvent);
335     }
336
337     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
338             throws SAXException JavaDoc {
339
340         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_ELEMENT);
341         saxEvent.addParm(namespaceURI);
342         saxEvent.addParm(localName);
343         saxEvent.addParm(qName);
344         events.add(saxEvent);
345
346         // check to see if a we issued a start prefix mapping event
347
// for DOMDocument namespace decls
348

349         QName elementName = null;
350         if (namespaceURI != null) {
351             elementName = new QName(localName, Namespace.get(namespaceURI));
352         } else {
353             elementName = new QName(localName);
354         }
355
356         List JavaDoc prefixes = (List JavaDoc) prefixMappings.get(elementName);
357         if (prefixes != null) {
358             Iterator JavaDoc itr = prefixes.iterator();
359             while (itr.hasNext()) {
360                 SAXEvent prefixEvent =
361                         new SAXEvent(SAXEvent.END_PREFIX_MAPPING);
362                 prefixEvent.addParm(itr.next());
363                 events.add(prefixEvent);
364             }
365         }
366
367     }
368
369     public void characters(char[] ch, int start, int end) throws SAXException JavaDoc {
370         SAXEvent saxEvent = new SAXEvent(SAXEvent.CHARACTERS);
371         saxEvent.addParm(ch);
372         saxEvent.addParm(new Integer JavaDoc(start));
373         saxEvent.addParm(new Integer JavaDoc(end));
374         events.add(saxEvent);
375     }
376
377     // LexicalHandler interface
378
// -------------------------------------------------------------------------
379
public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
380             throws SAXException JavaDoc {
381         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_DTD);
382         saxEvent.addParm(name);
383         saxEvent.addParm(publicId);
384         saxEvent.addParm(systemId);
385         events.add(saxEvent);
386     }
387
388     public void endDTD() throws SAXException JavaDoc {
389         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_DTD);
390         events.add(saxEvent);
391     }
392
393     public void startEntity(String JavaDoc name) throws SAXException JavaDoc {
394         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_ENTITY);
395         saxEvent.addParm(name);
396         events.add(saxEvent);
397     }
398
399     public void endEntity(String JavaDoc name) throws SAXException JavaDoc {
400         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_ENTITY);
401         saxEvent.addParm(name);
402         events.add(saxEvent);
403     }
404
405     public void startCDATA() throws SAXException JavaDoc {
406         SAXEvent saxEvent = new SAXEvent(SAXEvent.START_CDATA);
407         events.add(saxEvent);
408     }
409
410     public void endCDATA() throws SAXException JavaDoc {
411         SAXEvent saxEvent = new SAXEvent(SAXEvent.END_CDATA);
412         events.add(saxEvent);
413     }
414
415     public void comment(char[] ch, int start, int end) throws SAXException JavaDoc {
416         SAXEvent saxEvent = new SAXEvent(SAXEvent.COMMENT);
417         saxEvent.addParm(ch);
418         saxEvent.addParm(new Integer JavaDoc(start));
419         saxEvent.addParm(new Integer JavaDoc(end));
420         events.add(saxEvent);
421     }
422
423     // DeclHandler interface
424
// -------------------------------------------------------------------------
425
public void elementDecl(String JavaDoc name, String JavaDoc model) throws SAXException JavaDoc {
426         SAXEvent saxEvent = new SAXEvent(SAXEvent.ELEMENT_DECL);
427         saxEvent.addParm(name);
428         saxEvent.addParm(model);
429         events.add(saxEvent);
430     }
431
432     public void attributeDecl(String JavaDoc eName, String JavaDoc aName, String JavaDoc type,
433             String JavaDoc valueDefault, String JavaDoc value) throws SAXException JavaDoc {
434         SAXEvent saxEvent = new SAXEvent(SAXEvent.ATTRIBUTE_DECL);
435         saxEvent.addParm(eName);
436         saxEvent.addParm(aName);
437         saxEvent.addParm(type);
438         saxEvent.addParm(valueDefault);
439         saxEvent.addParm(value);
440         events.add(saxEvent);
441     }
442
443     public void internalEntityDecl(String JavaDoc name, String JavaDoc value)
444             throws SAXException JavaDoc {
445         SAXEvent saxEvent = new SAXEvent(SAXEvent.INTERNAL_ENTITY_DECL);
446         saxEvent.addParm(name);
447         saxEvent.addParm(value);
448         events.add(saxEvent);
449     }
450
451     public void externalEntityDecl(String JavaDoc name, String JavaDoc publicId, String JavaDoc sysId)
452             throws SAXException JavaDoc {
453         SAXEvent saxEvent = new SAXEvent(SAXEvent.EXTERNAL_ENTITY_DECL);
454         saxEvent.addParm(name);
455         saxEvent.addParm(publicId);
456         saxEvent.addParm(sysId);
457         events.add(saxEvent);
458     }
459
460     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
461         if (events == null) {
462             out.writeByte(NULL);
463         } else {
464             out.writeByte(OBJECT);
465             out.writeObject(events);
466         }
467     }
468
469     public void readExternal(ObjectInput JavaDoc in) throws ClassNotFoundException JavaDoc,
470             IOException JavaDoc {
471         if (in.readByte() != NULL) {
472             events = (List JavaDoc) in.readObject();
473         }
474     }
475
476     // SAXEvent inner class
477
// -------------------------------------------------------------------------
478
static class SAXEvent implements Externalizable JavaDoc {
479         public static final long serialVersionUID = 1;
480
481         static final byte PROCESSING_INSTRUCTION = 1;
482
483         static final byte START_PREFIX_MAPPING = 2;
484
485         static final byte END_PREFIX_MAPPING = 3;
486
487         static final byte START_DOCUMENT = 4;
488
489         static final byte END_DOCUMENT = 5;
490
491         static final byte START_ELEMENT = 6;
492
493         static final byte END_ELEMENT = 7;
494
495         static final byte CHARACTERS = 8;
496
497         static final byte START_DTD = 9;
498
499         static final byte END_DTD = 10;
500
501         static final byte START_ENTITY = 11;
502
503         static final byte END_ENTITY = 12;
504
505         static final byte START_CDATA = 13;
506
507         static final byte END_CDATA = 14;
508
509         static final byte COMMENT = 15;
510
511         static final byte ELEMENT_DECL = 16;
512
513         static final byte ATTRIBUTE_DECL = 17;
514
515         static final byte INTERNAL_ENTITY_DECL = 18;
516
517         static final byte EXTERNAL_ENTITY_DECL = 19;
518
519         protected byte event;
520
521         protected List JavaDoc parms;
522
523         public SAXEvent() {
524         }
525
526         SAXEvent(byte event) {
527             this.event = event;
528         }
529
530         void addParm(Object JavaDoc parm) {
531             if (parms == null) {
532                 parms = new ArrayList JavaDoc(3);
533             }
534
535             parms.add(parm);
536         }
537
538         Object JavaDoc getParm(int index) {
539             if ((parms != null) && (index < parms.size())) {
540                 return parms.get(index);
541             } else {
542                 return null;
543             }
544         }
545
546         public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
547             out.writeByte(event);
548
549             if (parms == null) {
550                 out.writeByte(NULL);
551             } else {
552                 out.writeByte(OBJECT);
553                 out.writeObject(parms);
554             }
555         }
556
557         public void readExternal(ObjectInput JavaDoc in) throws ClassNotFoundException JavaDoc,
558                 IOException JavaDoc {
559             event = in.readByte();
560
561             if (in.readByte() != NULL) {
562                 parms = (List JavaDoc) in.readObject();
563             }
564         }
565     }
566 }
567
568 /*
569  * Redistribution and use of this software and associated documentation
570  * ("Software"), with or without modification, are permitted provided that the
571  * following conditions are met:
572  *
573  * 1. Redistributions of source code must retain copyright statements and
574  * notices. Redistributions must also contain a copy of this document.
575  *
576  * 2. Redistributions in binary form must reproduce the above copyright notice,
577  * this list of conditions and the following disclaimer in the documentation
578  * and/or other materials provided with the distribution.
579  *
580  * 3. The name "DOM4J" must not be used to endorse or promote products derived
581  * from this Software without prior written permission of MetaStuff, Ltd. For
582  * written permission, please contact dom4j-info@metastuff.com.
583  *
584  * 4. Products derived from this Software may not be called "DOM4J" nor may
585  * "DOM4J" appear in their names without prior written permission of MetaStuff,
586  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
587  *
588  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
589  *
590  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
591  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
592  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
593  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
594  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
595  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
596  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
597  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
598  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
599  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
600  * POSSIBILITY OF SUCH DAMAGE.
601  *
602  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
603  */

604
Popular Tags