KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > storage > SAXHandler


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.mapper.storage;
24
25 import java.sql.SQLException JavaDoc;
26
27 import org.xml.sax.*;
28 import org.xml.sax.ext.LexicalHandler JavaDoc;
29 import org.xml.sax.helpers.DefaultHandler JavaDoc;
30 import org.xquark.mapper.RepositoryException;
31 import org.xquark.mapper.dbms.AbstractConnection;
32 import org.xquark.mapper.metadata.PathNode;
33 import org.xquark.mapper.metadata.RepositoryConstants;
34 import org.xquark.mapper.metadata.StoragePathMetadata;
35 import org.xquark.mapper.util.RepositoryProperties;
36 import org.xquark.schema.SchemaConstants;
37 import org.xquark.util.SAXConstants;
38 import org.xquark.xml.xdbc.XMLDBCException;
39 import org.xquark.xml.xdbc.XMLErrorHandler;
40 import org.xquark.xpath.NodeKind;
41
42 /** Class using SAX2 event handlers for building the optimized XML logical structure.
43  *
44  * <ul>
45  * <li>{@link org.xml.sax.ContentHandler ContentHandler}</li>
46  * </ul>
47  *
48  * @see org.xml.sax.ContentHandler
49  */

50 public class SAXHandler extends DefaultHandler JavaDoc
51 implements RepositoryConstants, LexicalHandler JavaDoc
52 {
53     private static final String JavaDoc RCSRevision = "$Revision: 1.1 $";
54     private static final String JavaDoc RCSName = "$Name: $";
55
56     ///////////////////////////////////////////
57
// Data
58
///////////////////////////////////////////
59

60     //
61
// storage data
62
//
63

64     /** JDBC related data for persistent storage. */
65     protected AbstractConnection connection;
66     protected boolean performCommit; // used instead of XMLConnection.getConnection() to work with Bridge
67

68     //
69
// Options
70
//
71
protected boolean removeWhitespace = false; // if true removes all character data containing only whitespaces
72

73     /* Algorithm variables */
74     public static final short UNKNOWN = 0;
75     static final short START = 0;
76     static final short END =1;
77     protected short lastEvent = UNKNOWN; // last event was start or end element ?
78
protected boolean textBetweenTransitions = false; // to determine if text is to be saved
79
protected PathIterator context; // Working node
80
protected StringBuffer JavaDoc textData;
81     protected AbstractModelBuilder builder;
82     protected Locator locator;
83     private boolean nsFeatureNotTested = true; // feature must be true
84

85     
86     /** Constructor
87      */

88     public SAXHandler(PathIterator metadataContext, AbstractConnection connection, AbstractModelBuilder builder)
89     throws XMLDBCException
90     {
91         context = metadataContext;
92         this.connection = connection;
93         this.builder = builder;
94         textData = new StringBuffer JavaDoc(256);
95     }
96     
97     /**
98      * Set the removeWhitespace option which if true removes all character data
99      * containing only whitespaces
100      *
101      * @param value new value of the option.
102      */

103     public void setRemoveWhitespace(boolean value)
104     {
105         this.removeWhitespace = value;
106     }
107     
108     public void reset() throws RepositoryException
109     {
110         context.reset();
111         try {
112             builder.reset();
113         }
114         catch (SQLException JavaDoc e) {
115             throw new RepositoryException(RepositoryException.DB_ERROR,
116                 "JDBC error while resetting dbms resources", e);
117         }
118         lastEvent = UNKNOWN;
119         textData.setLength(0);
120         textBetweenTransitions = false;
121         nsFeatureNotTested = true;
122     }
123     
124     private void clear() throws XMLDBCException
125     {
126         reset();
127         builder.clearBuffer();
128     }
129     
130     public void close() throws XMLDBCException
131     {
132          if (context != null)
133         {
134             context = null;
135             try
136             {
137                 builder.close();
138             }
139             catch (SQLException JavaDoc e)
140             {
141                 throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while closing storage buffer.", e);
142             }
143             builder = null;
144         }
145     }
146     
147     /**
148      * Perform JDBC statement cleaning before the object is destroyed.
149      *
150      * <p> Cleans what is to be cleaned. Store the tag (tag) dictionary</p>
151      *
152      * @exception org.xml.sax.SQLException if a database access error occurs.
153      * @see org.xml.sax.ContentHandler#endDocument
154      */

155     public void clean()
156     throws SQLException JavaDoc
157     {
158         // Save document longest path set to repository longest path set and database ? MADE UP TO NOW BY REPOSITORY.
159
}
160     
161     ////////////////////////////////////////////////////////////////////
162
// Implementation of ErrorHandler interface.
163
////////////////////////////////////////////////////////////////////
164
public void warning(SAXParseException ex) throws SAXException
165     {
166         processFatalError(new SAXException("Warning at line " + ex.getLineNumber()
167                           + " in " + ex.getSystemId() + ": " + ex.getMessage()));
168     }
169     
170     public void error(SAXParseException ex) throws SAXException
171     {
172         processFatalError(new SAXException("Error at line " + ex.getLineNumber()
173                           + " in " + ex.getSystemId() + ": " + ex.getMessage()));
174     }
175     
176     public void fatalError(SAXParseException ex) throws SAXException
177     {
178         processFatalError(new SAXException("Fatal error at line " + ex.getLineNumber()
179                           + " in " + ex.getSystemId() + ": " + ex.getMessage()));
180     }
181
182     //////////////////////////////////////////////////////
183
// Implementation of LexicalHandler interface.
184
//////////////////////////////////////////////////////
185
public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId) throws SAXException
186     {
187         //Debug.print("startDTD");
188
}
189
190     public void endDTD()throws SAXException
191     {
192         //Debug.print("endDTD");
193
}
194
195     public void startEntity(String JavaDoc name) throws SAXException
196     {
197         //Debug.print("startEntity");
198
}
199     
200     public void endEntity(String JavaDoc name) throws SAXException
201     {
202         //Debug.print("endEntity");
203
}
204     
205     public void startCDATA() throws SAXException
206     {
207         //Debug.print("startCDATA");
208
}
209     
210     public void endCDATA() throws SAXException
211     {
212         //Debug.print("endCDATA");
213
}
214     
215     public void comment(char ch[], int start, int length) throws SAXException
216     {
217         //Debug.print("comment");
218
}
219     
220     ////////////////////////////////////////////////////////////////////
221
// Implementation of ContentHandler interface.
222
////////////////////////////////////////////////////////////////////
223
public void startDocument() throws SAXException
224     {
225         //Debug.print("startDocument");
226
try
227         {
228             performCommit = connection.getConnection().getAutoCommit();
229             if (performCommit)
230                 connection.start(); // START TRANSACTION
231
startParsing();
232         }
233         catch(Exception JavaDoc e)
234         {
235             processFatalError(e);
236         }
237         
238     }
239     
240     public void endDocument() throws SAXException
241     {
242         //Debug.print("endDocument");
243
// Store the root node and perform flush
244

245         try
246         {
247             builder.endModel();
248             endParsing();
249             if (performCommit)
250             {
251                 flushBuffer();
252                 connection.commit();
253             }
254             // resource re-initialization
255
reset();
256         }
257         catch(Exception JavaDoc e)
258         {
259             processFatalError(e);
260         }
261     }
262     
263     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
264     throws SAXException
265     {
266         // no op
267
}
268     
269     public void startElement(String JavaDoc namespaceURI,String JavaDoc localName,String JavaDoc qName,Attributes atts)
270     throws SAXException
271     {
272         // test SAX feature for namespaces
273
if (nsFeatureNotTested)
274         {
275             if (localName.length() == 0)
276                 throw new SAXException("Your XML parser does not provide namespaces support. If you are using JAXP, make sure that setNamespaceAware(true) has been called on your parser factory.");
277             nsFeatureNotTested = false;
278         }
279     
280     
281         //Debug.print("startElement element : " + qName);
282
PathNode tmpPath;
283         
284         try
285         {
286             if (textBetweenTransitions())
287             {
288                 // create a model node for "mixed" text
289
builder.leafNode(NodeKind.TEXT, context.getStoragePathMetadata(), textData.toString(), locator);
290                 textData.setLength(0);
291                 textBetweenTransitions = false;
292             }
293             
294             // create a model node and a path set node for the element
295
builder.newNode(context.push(namespaceURI, localName), locator); // do not put the root path in the path set (already in)
296

297             if (context.getStoragePathMetadata() != null) // not out of storage
298
{
299                 //////////////////////////////////////////
300
// Prefixes storage
301
//////////////////////////////////////////
302
processPrefixes();
303                 
304                 //////////////////////////////////////////
305
// Attribute storage
306
//////////////////////////////////////////
307
int nbAtt = atts.getLength();
308                 StoragePathMetadata attNode;
309                 String JavaDoc uri; // because atts may be implemented by DOM2SAXAttrs that is dynamic
310

311                 // For each attribute
312
for(int i = 0; i < nbAtt; i++)
313                 {
314                     uri = atts.getURI(i);
315                     
316                     // discard namespace attributes (should not be : tolerance)
317
if (uri.equals(SAXConstants.XMLNS_URI))
318                         continue;
319                     
320                     // Test if it is the xsi:null attribute (do not save)
321
if (uri.equals(SchemaConstants.XSI_URI))
322                         builder.setXSIinfo(atts.getLocalName(i), atts.getValue(i)); // set element to null
323
else // save attribute
324
{
325                         // add the attribute path to path set
326
attNode = context.createNode(uri, atts.getLocalName(i), NodeKind.ATTRIBUTE);
327                         
328                         // create a model node for attribute definition
329
if (attNode != null) // may be null for Bridge
330
builder.leafNode(NodeKind.ATTRIBUTE, attNode, atts.getValue(i), locator);
331                     }
332                 }
333                 lastEvent = START;
334             }
335         }
336         catch(Exception JavaDoc e)
337         {
338             processFatalError(e);
339         }
340     }
341
342     /* Detached to provide a control when a path is not found.
343      * With Mapper it is allowed since there is no path set.
344      */

345     protected StoragePathMetadata push(String JavaDoc namespaceURI, String JavaDoc localName)
346     throws SAXException, RepositoryException
347     {
348         return context.push(namespaceURI, localName);
349     }
350
351     
352     protected void processPrefixes()
353     throws XMLDBCException, SQLException JavaDoc
354     {
355         // no op
356
}
357     
358     public void endElement(String JavaDoc namespaceURI,String JavaDoc localName,String JavaDoc qName) throws SAXException
359     {
360         try
361         {
362             if (context.getStoragePathMetadata() != null)
363             {
364                 if (textBetweenTransitions())
365                 {
366                     switch (lastEvent)
367                     {
368                         case START:
369                             builder.setData(textData.toString());
370                             break;
371                         case END:
372                             // create a model node for "mixed" text
373
builder.leafNode(NodeKind.TEXT, context.getStoragePathMetadata(),
374                             textData.toString(), locator);
375                             break;
376                         default:
377                     }
378                     
379                     textData.setLength(0);
380                     textBetweenTransitions = false;
381                 }
382                 
383                 // Achieve element node construction
384
builder.finalizeNode(locator);
385             }
386             context.pop();
387             lastEvent = END;
388         }
389         catch(Exception JavaDoc e)
390         {
391             processFatalError(e);
392         }
393         
394     }
395     
396     public void characters(char ch[], int start, int length)
397     throws SAXException
398     {
399         if (context.getStoragePathMetadata() != null)
400         {
401             //Debug.print("Characters");
402

403             // Store the characters in the StringBuffer because as PI or Comment
404
// are ignored from a value point of view
405
textData.append(ch, start, length);
406             
407             // Offset for PI & comments update
408
textBetweenTransitions=true;
409             builder.incCharOffset(length);
410         }
411     }
412     
413     protected boolean textBetweenTransitions()
414     {
415         return textBetweenTransitions;
416     }
417           
418     public void processingInstruction(String JavaDoc target, String JavaDoc data) throws SAXException
419     {
420         // no op
421
}
422     
423     public void setDocumentLocator(Locator locator)
424     {
425         //Debug.print("setDocumentLocator");
426
this.locator = locator;
427     }
428     
429     ////////////////////////////////////////////////
430
// STORAGE METHODS
431
////////////////////////////////////////////////
432
/** Saves an XML document in this repository from a SAX 2.0 source. The
433      * external SAX parser is responsible for parsing and validating documents.
434      * @param reader The SAX XMLReader used for parsing the document.
435      * The parser is assumed to be SAX 2.0 compliant.
436      * @param source the URL or stream where document can be found.
437      * @param ID The internal name used to identify the document in
438      * the repository. If null, the internal generated numeric handle is used.
439      * @return the ID of the document passed as a parameter.
440      * @throws RepositoryException Application exception.
441      */

442     protected void startParsing() throws RepositoryException, SQLException JavaDoc
443     {
444         setRemoveWhitespace(RepositoryProperties.getBooleanProperty(CONF_TRIM_WS));
445     }
446     
447     protected void endParsing() throws Exception JavaDoc
448     {
449     }
450     
451     protected void processFatalError(Exception JavaDoc e) throws SAXException
452     {
453         try
454         {
455             connection.rollback();
456              // restore JDBC autocommit mode
457
if (performCommit)
458                 connection.getConnection().setAutoCommit(performCommit);
459         }
460         catch (SQLException JavaDoc ex)
461         {
462             // TO DO : change JDBC connection !
463
}
464         finally
465         {
466             try
467             {
468                 clear(); // internal clear()
469
}
470             catch (XMLDBCException exc)
471             {
472                 // no op
473
}
474         }
475         if (e instanceof SAXException)
476             throw (SAXException)e;
477         if (e instanceof RepositoryException)
478             throw new SAXException("Application error during document storage.", e);
479         else if (e instanceof SQLException JavaDoc)
480             throw new SAXException("JDBC error during document storage.", e);
481         else // e.g. RuntimeException
482
throw new SAXException("Runtime error during document storage.", e);
483     }
484     
485     
486     ///////////////////////////////////////////////////////////////////////////
487
// XDBC implementation methods
488
///////////////////////////////////////////////////////////////////////////
489

490     public void setErrorHandler(XMLErrorHandler handler)
491     {
492         if (handler == null)
493             throw new NullPointerException JavaDoc("An error handler must be provided if you use the setErrorHandler() method.");
494         builder.setErrorHandler(handler);
495     }
496     
497     public void flushBuffer() throws XMLDBCException
498     {
499         builder.flushBuffer();
500     }
501     
502     public void clearBuffer() throws XMLDBCException
503     {
504         builder.clearBuffer();
505     }
506     
507     public void setAutoFlush(boolean mode) throws XMLDBCException
508     {
509         builder.setAutoFlush(mode);
510     }
511     
512     public boolean getAutoFlush()
513     {
514         return builder.getAutoFlush();
515     }
516     
517     public XMLErrorHandler getXMLErrorHandler()
518     {
519         return builder.getXMLErrorHandler();
520     }
521 }
522
523
524
Popular Tags