KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ozoneDB > xml > util > XMLContainer


1 // You can redistribute this software and/or modify it under the terms of
2
// the Ozone Library License version 1 published by ozone-db.org.
3
//
4
// The original code and portions created by SMB are
5
// Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
6
//
7
// $Id$
8

9 package org.ozoneDB.xml.util;
10
11 import java.io.IOException JavaDoc;
12 import java.io.ObjectOutput JavaDoc;
13 import java.io.ObjectInput JavaDoc;
14 import java.io.Externalizable JavaDoc;
15 import org.ozoneDB.*;
16 import org.w3c.dom.Document JavaDoc;
17 import org.w3c.dom.Node JavaDoc;
18 import org.w3c.dom.NodeList JavaDoc;
19 import org.xml.sax.ContentHandler JavaDoc;
20 import org.infozone.tools.xml.queries.XObject;
21 import org.ozoneDB.xml.dom.DocumentProxy;
22
23 /**
24  * <p>This class is the central part of the ozone/XML API. Basically it provides a
25  * persistent container for a XML document, which is stored in an ozone database.</p>
26  *
27  * <p><dl><dt>IMPORTANT:</dt><dd>Before calling one of the store or extract methods the
28  * thread <b>must</b> have joined a transaction.</dd></dl>
29  * </p>
30  *
31  * Usage of the SAX methods is recomended, because of the better performance.
32  *
33  * @version $Revision$ $Date$
34  * @author <a HREF="http://www.smb-tec.com">SMB</a>
35  */

36 public class XMLContainer implements Externalizable JavaDoc, SAXChunkProducerDelegate {
37
38     // Class data
39
public final static boolean debug = false;
40
41     // Data
42
private XMLContainerHelper helper;
43     private transient OzoneInterface db;
44     private transient Document JavaDoc doc;
45     /** True if this object runs outside an ozone server. */
46     private transient boolean runsExternal;
47
48     // Class methods
49

50     /**
51      * Creates a new container with the given name.
52      * @param _db The database where the container will be stored.
53      * @param _docName The name of the container (and the document).
54      * @return the new container.
55      */

56     public static XMLContainer newContainer(OzoneInterface _db, String JavaDoc _docName) throws Exception JavaDoc {
57         XMLContainerHelper helper = (XMLContainerHelper) _db.createObject(
58                 "org.ozoneDB.xml.util.XMLContainerHelperImpl",
59                 OzoneInterface.Public,
60                 _docName);
61         return new XMLContainer(_db, helper);
62     }
63     /**
64      * Returns the XMLContainer representing the document with the given name.
65      * @param _db The database where the container is stored.
66      * @param _docName The name under which the container has been stored.
67      * @return the container for the given name or null if the container
68      * does not exist.
69      */

70     public static XMLContainer forName(OzoneInterface _db, String JavaDoc _docName) throws Exception JavaDoc {
71         XMLContainerHelper helper = (XMLContainerHelper) _db.objectForName(_docName);
72         return helper != null ? new XMLContainer(_db, helper) : null;
73     }
74
75     /**
76      * Returns the XMLContainer representing the document the given node
77      * belongs to.
78      * @param _db The database where the container is stored.
79      * @param _pNode A node of the document the container represents.
80      * @return the container for the given node or null if the node has not
81      * been stored using the XMLContainer class.
82      */

83     public static XMLContainer forNode(OzoneInterface _db, Node JavaDoc _pNode) throws Exception JavaDoc {
84         if (!(_pNode instanceof OzoneProxy)) {
85             throw new IllegalArgumentException JavaDoc("Not a persistent DOM node: " + _pNode.getClass().getName());
86         }
87         DocumentProxy pDoc = _pNode instanceof Document JavaDoc
88                 ? (DocumentProxy) _pNode
89                 : (DocumentProxy) _pNode.getOwnerDocument();
90         XMLContainerHelper helper = pDoc.getContainer();
91         return helper != null ? new XMLContainer(_db, helper) : null;
92     }
93
94     // Constructors
95

96     protected XMLContainer(OzoneInterface _db, XMLContainerHelper _helper) {
97         db = _db;
98         helper = _helper;
99         runsExternal = (db instanceof ExternalDatabase);
100     }
101
102     // Methods
103

104     /**
105      * Changes the name of this container.
106      * @param _name The new name of this container or null to remove the
107      * current name.
108      */

109     public void setName(String JavaDoc _name) throws Exception JavaDoc {
110         if (helper == null) {
111             throw new IllegalStateException JavaDoc("Document has already been deleted.");
112         }
113         db.nameObject(helper, _name);
114     }
115
116     /**
117      * Deletes the container (and the associated document) from the database.
118      */

119     public synchronized void delete() throws Exception JavaDoc {
120         if (helper == null) {
121             throw new IllegalStateException JavaDoc("Document has already been deleted.");
122         }
123         db.deleteObject(helper);
124         helper = null;
125         doc = null;
126     }
127
128     /**
129      * Get the underlying persistent document that this container is working on.
130      * @return The persistent document.
131      */

132     public Document JavaDoc getPDocument() throws Exception JavaDoc {
133         if (helper == null) {
134             throw new IllegalStateException JavaDoc("Document has already been deleted.");
135         }
136         // not synchronized because it wouldn't make a difference here
137
if (doc == null) {
138             doc = helper.getDocument();
139         }
140         return doc;
141     }
142
143     /**
144      * Stores a transient DOM tree database. The newly created Nodes are
145      * appended to the Document Node of this container.
146      *
147      * @see #storeDOM(Node, Node)
148      */

149     public void storeDOM(Document JavaDoc _tNode) throws Exception JavaDoc {
150         if (helper == null)
151             throw new IllegalStateException JavaDoc("Document has already been deleted.");
152         storeDOM(null, _tNode);
153     }
154
155     /**
156      * Stores a transient node into the database.
157      *
158      * <p>Before calling this method the current thread <b>must</b> have joined an
159      * {@link org.ozoneDB.ExternalTransaction explicit Transaction}. This is an
160      * exception to the normal case, where an implicit transaction (handled by
161      * Ozone) is more appropriate.</p>
162      * <p><dl><dt>Note:</dt><dd>If ever possible the corresponding
163      * {@link #storeSAX(Node) SAX method} should be used, because the performance
164      * of SAX storage is much better.</dd></dl></p>
165      *
166      * @param _pNode The persistent node where the stored node will be appended to.
167      * Null replaces the current document.
168      * @param _tNode The transient node to be stored.
169      *
170      * @throws IllegalStateException if the underlying document has already been deleted.
171      * @throws IllegalArgumentException if _tnode was null.
172      * @throws IllegalStateException if the current thread has not joined a
173      * {@link org.ozoneDB.ExternalTransaction transaction}.
174      * @see org.ozoneDB.ExternalTransaction
175      * @see org.ozoneDB.ExternalDatabase#newTransaction()
176      */

177     public void storeDOM(Node JavaDoc _pNode, Node JavaDoc _tNode) throws Exception JavaDoc {
178         long time = 0;
179         long starttime = 0;
180         if (helper == null) {
181             throw new IllegalStateException JavaDoc("Document has already been deleted.");
182         }
183         if (_tNode == null) {
184             throw new IllegalArgumentException JavaDoc("tNode == null.");
185         }
186         // thread must have joined a transaction
187
if (runsExternal && ((ExternalDatabase) db).currentTransaction() == null) {
188             throw new IllegalStateException JavaDoc("Thread must have joined a transaction!");
189         }
190         if (_pNode == null) {
191             System.out.println("replacing document content");
192             //clearDocument();
193
}
194         SAXChunkConsumer consumer = helper.beginInputSequence(_pNode);
195         ModifiableNodeList mnl = new ModifiableNodeList(1);
196         mnl.addNode(_tNode);
197         SAXChunkProducer producer = new SAXChunkProducer(mnl);
198         ChunkOutputStream cos = producer.chunkStream();
199         do {
200             cos.reset();
201             producer.createNextChunk();
202             if (XMLContainer.debug) {
203                 starttime = System.currentTimeMillis();
204             }
205             consumer = helper.putChunk(cos.toByteArray(), consumer);
206             if (XMLContainer.debug) {
207                 time += (System.currentTimeMillis() - starttime);
208             }
209         } while (!cos.getEndFlag());
210         if (XMLContainer.debug) {
211             System.out.println("DOM store: store in db time: " + time + " ms");
212         }
213     }
214
215     /**
216      * Stores a DOM tree represented by SAX events in the datasabase. The
217      * newly created Nodes are appended to the Document Node of this container.
218      *
219      * @see #storeSAX(Node)
220      */

221     public ContentHandler JavaDoc storeSAX() throws Exception JavaDoc {
222         if (helper == null) {
223             throw new IllegalStateException JavaDoc("Document has already been deleted.");
224         }
225         return storeSAX(null);
226     }
227
228     /**
229      * Stores XML represented by SAX events into the database.
230      * <p>The entire storage process <b>must</b> be enclosed by an
231      * {@link org.ozoneDB.ExternalTransaction explicit Transaction}. This is an
232      * exception to the normal case, where an implicit transaction (handled by
233      * Ozone) is more appropriate. The storage process starts with the call to this
234      * method and ends with the last event send to the content handler. The SAX
235      * events must be properly terminated, i.e. there must be an end event for
236      * for every start event, otherwise the correct storage can't be guaranteed.</p>
237      *
238      * @param _pNode The persistent node where the stored data will be appended to.
239      *
240      * @return the content handler which stores all XML data it recieves into the
241      * database.
242      *
243      * @throws IllegalStateException if the underlying document has already been deleted.
244      * @throws IllegalStateException if the current thread has not joined a
245      * {@link org.ozoneDB.ExternalTransaction transaction}.
246      * @see org.ozoneDB.ExternalTransaction
247      * @see org.ozoneDB.ExternalDatabase#newTransaction()
248      */

249     public ContentHandler JavaDoc storeSAX(Node JavaDoc _pNode) throws Exception JavaDoc {
250         if (helper == null) {
251             throw new IllegalStateException JavaDoc("Document has already been deleted.");
252         }
253         // thread must have joined a transaction
254
if (runsExternal && ((ExternalDatabase) db).currentTransaction() == null) {
255             throw new IllegalStateException JavaDoc("Thread must have joined a transaction!");
256         }
257
258         // this eventually blocks if there is another thread storing something already
259
SAXChunkConsumer consumer = helper.beginInputSequence(_pNode);
260         SAXChunkProducer producer = new SAXChunkProducer(this);
261         producer.dbConsumer = consumer;
262         return producer;
263     }
264
265     /**
266      * This method is for internal use only. <b>Don't call it directly.</b>
267      */

268     public void processChunk(SAXChunkProducer _producer) throws Exception JavaDoc {
269         if (XMLContainer.debug) {
270             System.out.print("XMLContainer.processChunk()... ");
271         }
272         ChunkOutputStream cos = _producer.chunkStream();
273         if (XMLContainer.debug) {
274             System.out.print("putChunk(" + cos.count + ")... ");
275         }
276         _producer.dbConsumer = helper.putChunk(cos.toByteArray(), _producer.dbConsumer);
277     }
278
279     /**
280      * @see #extractDOM(Document, Node, Node , int)
281      */

282     public Document JavaDoc extractDOM(Document JavaDoc _domFactory) throws Exception JavaDoc {
283         return (Document JavaDoc) extractDOM(_domFactory, (Node JavaDoc) null, null, -1);
284     }
285
286     /**
287      * @see #extractDOM(Document, Node, Node , int)
288      */

289     public Node JavaDoc extractDOM(Document JavaDoc _domFactory, Node JavaDoc _pNode, Node JavaDoc _appendTo) throws Exception JavaDoc {
290         return extractDOM(_domFactory, _pNode, _appendTo, -1);
291     }
292
293     /**
294      * Extracts a given DOM node and all its descendants.
295      *
296      * <p>Before calling this method the current thread <b>must</b> have joined an
297      * {@link org.ozoneDB.ExternalTransaction explicit Transaction}. This is an
298      * exception to the normal case, where an implicit transaction (handled by
299      * Ozone) is more appropriate.</p>
300      *
301      * <p><dl><dt>Note:</dt><dd>If possible, the corresponding
302      * {@link #extractSAX(ContentHandler) SAX method} should be used, because the
303      * performance of SAX retrieval is much better.</dd></dl></p>
304      *
305      * @param _domFactory The DOM Document that is used to create the extracted DOM nodes.
306      * @param _pNode The persistent DOM node
307      * @param _appendTo The transient DOM node where the extracted content will
308      * will be appended to.
309      * @param _depth The number of hierarchy steps that should be extracted or
310      * null if the entire hierarchy should be extracted.
311      */

312     public Node JavaDoc extractDOM(Document JavaDoc _domFactory, Node JavaDoc _pNode, Node JavaDoc _appendTo, int _depth) throws Exception JavaDoc {
313         ModifiableNodeList mnl = null;
314         if (_pNode != null) {
315             mnl = new ModifiableNodeList(1);
316             mnl.addNode(_pNode);
317         }
318
319         NodeList JavaDoc resultList = extractDOM(_domFactory, mnl, _appendTo, _depth);
320         return resultList.item(0);
321
322 /* if (helper == null) {
323             throw new IllegalStateException ("Document has already been deleted.");
324         }
325         // thread must have joined a transaction
326         if (runsExternal && ((ExternalDatabase)db).currentTransaction() == null) {
327             throw new IllegalStateException( "Thread must have joined a transaction!" );
328         }
329
330         SAXChunkProducer producer = helper.beginOutputSequence( _pNode, _depth );
331         SAXChunkConsumer consumer = new SAXChunkConsumer(_domFactory, _appendTo);
332         ChunkOutputStream cos;
333         do {
334             producer = helper.createNextChunk( producer );
335             cos = producer.chunkStream();
336             consumer.processChunk( cos.toByteArray() );
337             cos.reset();
338         } while (!cos.getEndFlag());
339         return consumer.getResultNode();*/

340     }
341
342     public NodeList JavaDoc extractDOM(Document JavaDoc _domFactory, NodeList JavaDoc _pNodes, Node JavaDoc _appendTo, int _depth) throws Exception JavaDoc {
343         if (helper == null) {
344             throw new IllegalStateException JavaDoc("Document has already been deleted.");
345         }
346         // thread must have joined a transaction
347
if (runsExternal && ((ExternalDatabase) db).currentTransaction() == null) {
348             throw new IllegalStateException JavaDoc("Thread must have joined a transaction!");
349         }
350         SAXChunkProducer producer = helper.beginOutputSequence(_pNodes, _depth);
351         SAXChunkConsumer consumer = new SAXChunkConsumer(_domFactory, _appendTo);
352         ChunkOutputStream cos;
353         do {
354             producer = helper.createNextChunk(producer);
355             cos = producer.chunkStream();
356             consumer.processChunk(cos.toByteArray());
357             cos.reset();
358         } while (!cos.getEndFlag());
359         return consumer.getResultNodeList();
360     }
361
362     /**
363      * @see #extractSAX(ContentHandler, Node, int)
364      */

365     public void extractSAX(ContentHandler JavaDoc _contentHandler) throws Exception JavaDoc {
366         extractSAX(_contentHandler, null, -1);
367     }
368
369     /**
370      * @see #extractSAX(ContentHandler, Node , int )
371      */

372     public void extractSAX(ContentHandler JavaDoc _contentHandler, Node JavaDoc _pNode) throws Exception JavaDoc {
373         extractSAX(_contentHandler, _pNode, -1);
374     }
375
376     /**
377      * Extracts a given DOM node and all its descendants.
378      *
379      * <p>Before calling this method the current thread <b>must</b> have joined an
380      * {@link org.ozoneDB.ExternalTransaction explicit Transaction}. This is an
381      * exception to the normal case, where an implicit transaction (handled by
382      * Ozone) is more appropriate.</p>
383      *
384      * @param _contentHandler The ContentHandler that will receive the generated
385      * SAX events.
386      * @param _pNode The persistent DOM node that is the starting point, or null
387      * if the entire document should be extracted.
388      * @param _depth The number of hierarchy steps that should be extracted or
389      * null if the entire hierarchy should be extracted.
390      */

391     public void extractSAX(ContentHandler JavaDoc _contentHandler, Node JavaDoc _pNode, int _depth) throws Exception JavaDoc {
392         if (helper == null) {
393             throw new IllegalStateException JavaDoc("Document has already been deleted.");
394         }
395         // thread must have joined a transaction
396
if (runsExternal && ((ExternalDatabase) db).currentTransaction() == null) {
397             throw new IllegalStateException JavaDoc("Thread must have joined a transaction!");
398         }
399         ModifiableNodeList mnl = null;
400         if (_pNode != null) {
401             mnl = new ModifiableNodeList(1);
402             mnl.addNode(_pNode);
403         }
404         SAXChunkProducer producer = helper.beginOutputSequence(mnl, _depth);
405         SAXChunkConsumer consumer = new SAXChunkConsumer(_contentHandler);
406         ChunkOutputStream cos;
407         do {
408             producer = helper.createNextChunk(producer);
409             cos = producer.chunkStream();
410             consumer.processChunk(cos.toByteArray());
411             cos.reset();
412         } while (!cos.getEndFlag());
413     }
414
415     /**
416      * Create a new XUpdate query. XUpdate is a descriptive XML update
417      * language. XUpdate is the recommended way to change a document in the
418      * database. See <a HREF=http://www.xmldb.org>www.xmldb.org</a> for more
419      * information and some XUpdate documentation.
420      *
421      * @see OzoneXUpdateQuery
422      */

423     public OzoneXUpdateQuery newXUpdateQuery() {
424         return new OzoneXUpdateQuery(this);
425     }
426
427     /**
428      * Create a new XPath query.
429      *
430      * @see OzoneXPathQuery
431      */

432     public OzoneXPathQuery newXPathQuery() {
433         return new OzoneXPathQuery(this);
434     }
435
436     protected void executeXUpdate(OzoneXUpdateQuery _query) throws Exception JavaDoc {
437         if (_query == null) {
438             throw new IllegalArgumentException JavaDoc("_query == null.");
439         }
440         helper.executeXUpdate(_query);
441     }
442
443     protected XObject executeXPath(OzoneXPathQuery _query) throws Exception JavaDoc {
444         if (_query == null) {
445             throw new IllegalArgumentException JavaDoc("_query == null.");
446         }
447         return helper.executeXPath(_query);
448     }
449
450     /**
451      * Determines the absolute XPath for the given node.
452      *
453      * @param _pnode The W3C DOM node whose XPath is to determine.
454      * @return The string representing the absolute XPath for this node.
455      */

456     public String JavaDoc xpathForNode(Node JavaDoc _pnode) {
457         if (helper == null) {
458             throw new IllegalStateException JavaDoc("Document has already been deleted.");
459         }
460         return helper.xpathForNode(_pnode);
461     }
462
463     public void writeExternal(ObjectOutput JavaDoc _out) throws IOException JavaDoc {
464         if (runsExternal) {
465             throw new IllegalStateException JavaDoc("XMLContainer cannot be serialized outside an ozone server.");
466         }
467         _out.writeObject(helper);
468     }
469
470    public void readExternal(ObjectInput JavaDoc _in) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
471         if (runsExternal) {
472             throw new IllegalStateException JavaDoc("XMLContainer cannot be deserialized outside an ozone server.");
473         }
474         helper = (XMLContainerHelper) _in.readObject();
475         db = org.ozoneDB.core.Env.currentEnv().database;
476     }
477 }
478
Popular Tags