KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jelly > parser > XMLParser


1 /*
2  * Copyright 2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.jelly.parser;
17
18 import java.io.File JavaDoc;
19 import java.io.InputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.net.URL JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.EmptyStackException JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Properties JavaDoc;
29
30 import javax.xml.parsers.SAXParser JavaDoc;
31 import javax.xml.parsers.SAXParserFactory JavaDoc;
32
33 import org.apache.commons.collections.ArrayStack;
34
35 import org.apache.commons.jelly.JellyContext;
36 import org.apache.commons.jelly.JellyException;
37 import org.apache.commons.jelly.Script;
38 import org.apache.commons.jelly.Tag;
39 import org.apache.commons.jelly.TagLibrary;
40 import org.apache.commons.jelly.impl.CompositeTextScriptBlock;
41 import org.apache.commons.jelly.impl.ExpressionScript;
42 import org.apache.commons.jelly.impl.StaticTag;
43 import org.apache.commons.jelly.impl.ScriptBlock;
44 import org.apache.commons.jelly.impl.StaticTagScript;
45 import org.apache.commons.jelly.impl.TagFactory;
46 import org.apache.commons.jelly.impl.TagScript;
47 import org.apache.commons.jelly.impl.TextScript;
48 import org.apache.commons.jelly.util.ClassLoaderUtils;
49 import org.apache.commons.jelly.util.SAXParseException;
50 import org.apache.commons.jelly.expression.CompositeExpression;
51 import org.apache.commons.jelly.expression.ConstantExpression;
52 import org.apache.commons.jelly.expression.Expression;
53 import org.apache.commons.jelly.expression.ExpressionFactory;
54 import org.apache.commons.jelly.expression.jexl.JexlExpressionFactory;
55
56 import org.apache.commons.logging.Log;
57 import org.apache.commons.logging.LogFactory;
58
59 import org.xml.sax.Attributes JavaDoc;
60 import org.xml.sax.ErrorHandler JavaDoc;
61 import org.xml.sax.helpers.DefaultHandler JavaDoc;
62 import org.xml.sax.InputSource JavaDoc;
63 import org.xml.sax.Locator JavaDoc;
64 import org.xml.sax.SAXException JavaDoc;
65 import org.xml.sax.XMLReader JavaDoc;
66 import org.xml.sax.helpers.AttributesImpl JavaDoc;
67
68 /** <p><code>XMLParser</code> parses the XML Jelly format.
69  * The SAXParser and XMLReader portions of this code come from Digester.</p>
70  *
71  * @author <a HREF="mailto:jstrachan@apache.org">James Strachan</a>
72  * @version $Revision: 219726 $
73  */

74 public class XMLParser extends DefaultHandler JavaDoc {
75
76     /**
77      * Share the Jelly properties across parsers
78      */

79     private static Properties JavaDoc jellyProperties;
80
81
82     /** JellyContext which is used to locate tag libraries*/
83     private JellyContext context = new JellyContext();
84
85     /** the expression factory used to evaluate tag attributes */
86     private ExpressionFactory expressionFactory;
87
88     /** The current script block */
89     private ScriptBlock script;
90
91     /** The current, parent tagScript */
92     private TagScript tagScript;
93
94     /** The stack of body scripts. */
95     private ArrayStack scriptStack = new ArrayStack();
96
97     /** The stack of tagScripts - use ArrayList as it allows null. */
98     private ArrayList JavaDoc tagScriptStack = new ArrayList JavaDoc();
99
100     /** The current text buffer where non-custom tags get written */
101     private StringBuffer JavaDoc textBuffer;
102
103     /**
104      * The class loader to use for instantiating application objects.
105      * If not specified, the context class loader, or the class loader
106      * used to load XMLParser itself, is used, based on the value of the
107      * <code>useContextClassLoader</code> variable.
108      */

109     protected ClassLoader JavaDoc classLoader = null;
110
111     /**
112      * Do we want to use the Context ClassLoader when loading classes
113      * for instantiating new objects? Default is <code>false</code>.
114      */

115     protected boolean useContextClassLoader = false;
116
117     /**
118      * The application-supplied error handler that is notified when parsing
119      * warnings, errors, or fatal errors occur.
120      */

121     protected ErrorHandler JavaDoc errorHandler = null;
122
123     /**
124      * The SAXParserFactory that is created the first time we need it.
125      */

126     protected static SAXParserFactory JavaDoc factory = null;
127
128     /**
129      * The SAXParser we will use to parse the input stream.
130      */

131     protected SAXParser JavaDoc parser = null;
132
133     /**
134      * The XMLReader used to parse digester rules.
135      */

136     protected XMLReader JavaDoc reader = null;
137
138     /**
139      * The Locator associated with our parser.
140      */

141     protected Locator JavaDoc locator = null;
142
143     /**
144      * Registered namespaces we are currently processing. The key is the
145      * namespace prefix that was declared in the document. The value is an
146      * ArrayStack of the namespace URIs this prefix has been mapped to --
147      * the top Stack element is the most current one. (This architecture
148      * is required because documents can declare nested uses of the same
149      * prefix for different Namespace URIs).
150      */

151     protected Map JavaDoc namespaces = new HashMap JavaDoc();
152
153     /** The Map of the namespace prefix -&gt; URIs defined for the current element */
154     private Map JavaDoc elementNamespaces;
155
156     /**
157      * The name of the file being parsed that is passed to the TagScript objects
158      * for error reporting
159      */

160     private String JavaDoc fileName;
161
162     /**
163      * Do we want to use a validating parser?
164      */

165     protected boolean validating = false;
166
167     /** Flag to indicate if this object has been configured */
168     private boolean configured;
169
170     /**
171      * when not null, set the default namespace for
172      * unprefixed elements via the DefaultNamespaceFilter
173      * class
174      */

175     private String JavaDoc defaultNamespaceURI = null;
176
177     /**
178      * The Log to which logging calls will be made.
179      */

180     private Log log = LogFactory.getLog(XMLParser.class);
181
182     /**
183      * Construct a new XMLParser with default properties.
184      */

185     public XMLParser() {
186     }
187
188     /**
189      * Construct a new XMLParser, allowing a SAXParser to be passed in. This
190      * allows XMLParser to be used in environments which are unfriendly to
191      * JAXP1.1 (such as WebLogic 6.0). Thanks for the request to change go to
192      * James House (james@interobjective.com). This may help in places where
193      * you are able to load JAXP 1.1 classes yourself.
194      */

195     public XMLParser(SAXParser JavaDoc parser) {
196         this.parser = parser;
197     }
198
199     /**
200      * Construct a new XMLParser, allowing an XMLReader to be passed in. This
201      * allows XMLParser to be used in environments which are unfriendly to
202      * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you
203      * have to configure namespace and validation support yourself, as these
204      * properties only affect the SAXParser and emtpy constructor.
205      */

206     public XMLParser(XMLReader JavaDoc reader) {
207         this.reader = reader;
208     }
209
210     /**
211      * Parse the content of the specified file using this XMLParser. Returns
212      * the root element from the object stack (if any).
213      *
214      * @param file File containing the XML data to be parsed
215      *
216      * @exception IOException if an input/output error occurs
217      * @exception SAXException if a parsing exception occurs
218      */

219     public Script parse(File JavaDoc file) throws IOException JavaDoc, SAXException JavaDoc {
220         return parse(file.toURL());
221     }
222
223     /**
224      * Parse the content of the specified file using this XMLParser. Returns
225      * the root element from the object stack (if any).
226      *
227      * @param url URL containing the XML data to be parsed
228      *
229      * @exception IOException if an input/output error occurs
230      * @exception SAXException if a parsing exception occurs
231      */

232     public Script parse(URL JavaDoc url) throws IOException JavaDoc, SAXException JavaDoc {
233         ensureConfigured();
234         this.fileName = url.toString();
235
236         InputSource JavaDoc source = new InputSource JavaDoc(url.toString());
237
238         getXMLReader().parse(source);
239         return script;
240     }
241
242     /**
243      * Parse the content of the specified input source using this XMLParser.
244      * Returns the root element from the object stack (if any).
245      *
246      * @param input Input source containing the XML data to be parsed
247      *
248      * @exception IOException if an input/output error occurs
249      * @exception SAXException if a parsing exception occurs
250      */

251     public Script parse(InputSource JavaDoc input) throws IOException JavaDoc, SAXException JavaDoc {
252         ensureConfigured();
253         this.fileName = input.getSystemId();
254         getXMLReader().parse(input);
255         return script;
256     }
257
258     /**
259      * Parse the content of the specified input stream using this XMLParser.
260      * Returns the root element from the object stack (if any).
261      * (Note: if reading a File or URL, use one of the URL-based
262      * parse methods instead. This method will not be able
263      * to resolve any relative paths inside a DTD.)
264      *
265      * @param input Input stream containing the XML data to be parsed
266      * @return
267      * @exception IOException
268      * if an input/output error occurs
269      * @exception SAXException
270      * if a parsing exception occurs
271      */

272     public Script parse(InputStream JavaDoc input) throws IOException JavaDoc, SAXException JavaDoc {
273         ensureConfigured();
274         this.fileName = getCurrentURI();
275         getXMLReader().parse(new InputSource JavaDoc(input));
276         return script;
277     }
278
279     /**
280      * Parse the content of the specified reader using this XMLParser.
281      * Returns the root element from the object stack (if any).
282      * (Note: if reading a File or URL, use one of the URL-based
283      * parse methods instead. This method will not be able
284      * to resolve any relative paths inside a DTD.)
285      *
286      * @param reader Reader containing the XML data to be parsed
287      * @return
288      * @exception IOException
289      * if an input/output error occurs
290      * @exception SAXException
291      * if a parsing exception occurs
292      */

293     public Script parse(Reader JavaDoc reader) throws IOException JavaDoc, SAXException JavaDoc {
294         ensureConfigured();
295         this.fileName = getCurrentURI();
296         getXMLReader().parse(new InputSource JavaDoc(reader));
297         return script;
298     }
299
300     /**
301      * Parse the content of the specified URI using this XMLParser.
302      * Returns the root element from the object stack (if any).
303      *
304      * @param uri URI containing the XML data to be parsed
305      *
306      * @exception IOException if an input/output error occurs
307      * @exception SAXException if a parsing exception occurs
308      */

309     public Script parse(String JavaDoc uri) throws IOException JavaDoc, SAXException JavaDoc {
310         ensureConfigured();
311         this.fileName = uri;
312         getXMLReader().parse(uri);
313         return script;
314     }
315
316     /**
317      * Return the currently mapped namespace URI for the specified prefix,
318      * if any; otherwise return <code>null</code>. These mappings come and
319      * go dynamically as the document is parsed.
320      *
321      * @param prefix Prefix to look up
322      */

323     public String JavaDoc findNamespaceURI(String JavaDoc prefix) {
324         ArrayStack stack = (ArrayStack) namespaces.get(prefix);
325         if (stack == null) {
326             return (null);
327         }
328         try {
329             return ((String JavaDoc) stack.peek());
330         }
331         catch (EmptyStackException JavaDoc e) {
332             return (null);
333         }
334     }
335
336     // Properties
337
//-------------------------------------------------------------------------
338
public JellyContext getContext() {
339         return context;
340     }
341
342     public void setContext(JellyContext context) {
343         this.context = context;
344     }
345
346     /**
347      * Set the jelly namespace to use for unprefixed elements.
348      * Will be overridden by an explicit namespace in the
349      * XML document.
350      *
351      * @param namespace jelly namespace to use (e.g. 'jelly:core')
352      */

353     public void setDefaultNamespaceURI(String JavaDoc namespace) {
354         this.defaultNamespaceURI = namespace;
355     }
356
357     /**
358      * Return the class loader to be used for instantiating application objects
359      * when required. This is determined based upon the following rules:
360      * <ul>
361      * <li>The class loader set by <code>setClassLoader()</code>, if any</li>
362      * <li>The thread context class loader, if it exists and the
363      * <code>useContextClassLoader</code> property is set to true</li>
364      * <li>The class loader used to load the XMLParser class itself.
365      * </ul>
366      */

367     public ClassLoader JavaDoc getClassLoader() {
368         return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass());
369     }
370
371     /**
372      * Set the class loader to be used for instantiating application objects
373      * when required.
374      *
375      * @param classLoader The new class loader to use, or <code>null</code>
376      * to revert to the standard rules
377      */

378     public void setClassLoader(ClassLoader JavaDoc classLoader) {
379         this.classLoader = classLoader;
380     }
381
382     /**
383      * Return the boolean as to whether the context classloader should be used.
384      */

385     public boolean getUseContextClassLoader() {
386         return useContextClassLoader;
387     }
388
389     /**
390      * Determine whether to use the Context ClassLoader (the one found by
391      * calling <code>Thread.currentThread().getContextClassLoader()</code>)
392      * to resolve/load classes. If not
393      * using Context ClassLoader, then the class-loading defaults to
394      * using the calling-class' ClassLoader.
395      *
396      * @param use determines whether to use JellyContext ClassLoader.
397      */

398     public void setUseContextClassLoader(boolean use) {
399         useContextClassLoader = use;
400     }
401
402     /**
403      * Return the error handler for this XMLParser.
404      */

405     public ErrorHandler JavaDoc getErrorHandler() {
406         return (this.errorHandler);
407     }
408
409     /**
410      * Set the error handler for this XMLParser.
411      *
412      * @param errorHandler The new error handler
413      */

414     public void setErrorHandler(ErrorHandler JavaDoc errorHandler) {
415         this.errorHandler = errorHandler;
416     }
417
418     /**
419      * Return the current Logger associated with this instance of the XMLParser
420      */

421     public Log getLogger() {
422         return log;
423     }
424
425     /**
426      * Set the current logger for this XMLParser.
427      */

428     public void setLogger(Log log) {
429         this.log = log;
430     }
431
432     /** @return the expression factory used to evaluate tag attributes */
433     public ExpressionFactory getExpressionFactory() {
434         if (expressionFactory == null) {
435             expressionFactory = createExpressionFactory();
436         }
437         return expressionFactory;
438     }
439
440     /** Sets the expression factory used to evaluate tag attributes */
441     public void setExpressionFactory(ExpressionFactory expressionFactory) {
442         this.expressionFactory = expressionFactory;
443     }
444
445     /**
446      * Return the SAXParser we will use to parse the input stream. If there
447      * is a problem creating the parser, return <code>null</code>.
448      */

449     public SAXParser JavaDoc getParser() {
450         // Return the parser we already created (if any)
451
if (parser != null) {
452             return (parser);
453         }
454         // Create and return a new parser
455
synchronized (this) {
456             try {
457                 if (factory == null) {
458                     factory = SAXParserFactory.newInstance();
459                 }
460                 factory.setNamespaceAware(true);
461                 factory.setValidating(validating);
462                 parser = factory.newSAXParser();
463                 return (parser);
464             }
465             catch (Exception JavaDoc e) {
466                 log.error("XMLParser.getParser: ", e);
467                 return (null);
468             }
469         }
470     }
471
472     /**
473      * By setting the reader in the constructor, you can bypass JAXP and
474      * be able to use digester in Weblogic 6.0.
475      *
476      * @deprecated Use getXMLReader() instead, which can throw a
477      * SAXException if the reader cannot be instantiated
478      */

479     public XMLReader JavaDoc getReader() {
480         try {
481             return (getXMLReader());
482         }
483         catch (SAXException JavaDoc e) {
484             log.error("Cannot get XMLReader", e);
485             return (null);
486         }
487     }
488
489     /**
490      * Return the XMLReader to be used for parsing the input document.
491      *
492      * @exception SAXException if no XMLReader can be instantiated
493      */

494     public synchronized XMLReader JavaDoc getXMLReader() throws SAXException JavaDoc {
495         if (reader == null) {
496             reader = getParser().getXMLReader();
497             if (this.defaultNamespaceURI != null) {
498                 reader = new DefaultNamespaceFilter(this.defaultNamespaceURI,reader);
499             }
500         }
501         //set up the parse
502
reader.setContentHandler(this);
503         reader.setDTDHandler(this);
504         //reader.setEntityResolver(this);
505
reader.setErrorHandler(this);
506
507         return reader;
508     }
509
510     /**
511      * Return the validating parser flag.
512      */

513     public boolean getValidating() {
514         return (this.validating);
515     }
516
517     /**
518      * Set the validating parser flag. This must be called before
519      * <code>parse()</code> is called the first time.
520      *
521      * @param validating The new validating parser flag.
522      */

523     public void setValidating(boolean validating) {
524         this.validating = validating;
525     }
526
527
528     /**
529      * Returns the script that has just been created if this class is used
530      * as a SAX ContentHandler and passed into some XML processor or parser.
531      *
532      * @return the ScriptBlock created if SAX events are piped into this class,
533      * which must include a startDocument() and endDocument()
534      */

535     public ScriptBlock getScript() {
536         return script;
537     }
538
539
540     // ContentHandler interface
541
//-------------------------------------------------------------------------
542
/**
543      * Process notification of the beginning of the document being reached.
544      *
545      * @exception SAXException if a parsing error is to be reported
546      */

547     public void startDocument() throws SAXException JavaDoc {
548         script = new ScriptBlock();
549         textBuffer = new StringBuffer JavaDoc();
550         tagScript = null;
551         scriptStack.clear();
552         tagScriptStack.clear();
553     }
554
555     /**
556      * Process notification of the end of the document being reached.
557      *
558      * @exception SAXException if a parsing error is to be reported
559      */

560     public void endDocument() throws SAXException JavaDoc {
561         textBuffer = null;
562     }
563
564     /**
565      * Process notification of the start of an XML element being reached.
566      *
567      * @param namespaceURI The Namespace URI, or the empty string if the
568      * element has no Namespace URI or if Namespace processing is not
569      * being performed.
570      * @param localName The local name (without prefix), or the empty
571      * string if Namespace processing is not being performed.
572      * @param qName The qualified name (with prefix), or the empty
573      * string if qualified names are not available.\
574      * @param list The attributes attached to the element. If there are
575      * no attributes, it shall be an empty Attributes object.
576      * @exception SAXException if a parsing error is to be reported
577      */

578     public void startElement(
579         String JavaDoc namespaceURI,
580         String JavaDoc localName,
581         String JavaDoc qName,
582         Attributes JavaDoc list)
583         throws SAXException JavaDoc {
584
585         try {
586             // add check to ensure namespace URI is "" for no namespace
587
if ( namespaceURI == null ) {
588                 namespaceURI = "";
589             }
590
591             // if this is a tag then create a script to run it
592
// otherwise pass the text to the current body
593
TagScript newTagScript = createTag(namespaceURI, localName, list);
594             if (newTagScript == null) {
595                 newTagScript = createStaticTag(namespaceURI, localName, qName, list);
596             }
597             tagScript = newTagScript;
598             tagScriptStack.add(tagScript);
599             if (tagScript != null) {
600                 // set the line number details
601
if ( locator != null ) {
602                     tagScript.setLocator(locator);
603                 }
604                 // sets the file name element names
605
tagScript.setFileName(fileName);
606                 tagScript.setElementName(qName);
607                 tagScript.setLocalName(localName);
608
609                 if (textBuffer.length() > 0) {
610                     addTextScript(textBuffer.toString());
611                     textBuffer.setLength(0);
612                 }
613                 script.addScript(tagScript);
614                 // start a new body
615
scriptStack.push(script);
616                 script = new ScriptBlock();
617                 tagScript.setTagBody(script);
618             }
619             else {
620                 // XXXX: might wanna handle empty elements later...
621
textBuffer.append("<");
622                 textBuffer.append(qName);
623                 int size = list.getLength();
624                 for (int i = 0; i < size; i++) {
625                     textBuffer.append(" ");
626                     textBuffer.append(list.getQName(i));
627                     textBuffer.append("=");
628                     textBuffer.append("\"");
629                     textBuffer.append(list.getValue(i));
630                     textBuffer.append("\"");
631                 }
632                 textBuffer.append(">");
633             }
634         }
635         catch (SAXException JavaDoc e) {
636             throw e;
637         }
638         catch (Exception JavaDoc e) {
639             log.error( "Caught exception: " + e, e );
640             throw new SAXException JavaDoc( "Runtime Exception: " + e, e );
641         }
642     }
643
644     /**
645      * Process notification of character data received from the body of
646      * an XML element.
647      *
648      * @param buffer The characters from the XML document
649      * @param start Starting offset into the buffer
650      * @param length Number of characters from the buffer
651      *
652      * @exception SAXException if a parsing error is to be reported
653      */

654     public void characters(char buffer[], int start, int length)
655         throws SAXException JavaDoc {
656         textBuffer.append(buffer, start, length);
657     }
658
659     /**
660      * Process notification of the end of an XML element being reached.
661      *
662      * @param namespaceURI The Namespace URI, or the empty string if the
663      * element has no Namespace URI or if Namespace processing is not
664      * being performed.
665      * @param localName The local name (without prefix), or the empty
666      * string if Namespace processing is not being performed.
667      * @param qName The qualified XML 1.0 name (with prefix), or the
668      * empty string if qualified names are not available.
669      * @exception SAXException if a parsing error is to be reported
670      */

671     public void endElement(String JavaDoc namespaceURI, String JavaDoc localName, String JavaDoc qName)
672         throws SAXException JavaDoc {
673         try {
674             tagScript = (TagScript) tagScriptStack.remove(tagScriptStack.size() - 1);
675             if (tagScript != null) {
676                 if (textBuffer.length() > 0) {
677                     addTextScript(textBuffer.toString());
678                     textBuffer.setLength(0);
679                 }
680                 script = (ScriptBlock) scriptStack.pop();
681             }
682             else {
683                 textBuffer.append("</");
684                 textBuffer.append(qName);
685                 textBuffer.append(">");
686             }
687
688             // now lets set the parent tag variable
689
if ( tagScriptStack.isEmpty() ) {
690                 tagScript = null;
691             }
692             else {
693                 tagScript = (TagScript) tagScriptStack.get(tagScriptStack.size() - 1);
694             }
695         } catch (Exception JavaDoc e) {
696             log.error( "Caught exception: " + e, e );
697             throw new SAXException JavaDoc( "Runtime Exception: " + e, e );
698         }
699     }
700
701     /**
702      * Process notification that a namespace prefix is coming in to scope.
703      *
704      * @param prefix Prefix that is being declared
705      * @param namespaceURI Corresponding namespace URI being mapped to
706      *
707      * @exception SAXException if a parsing error is to be reported
708      */

709     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc namespaceURI)
710         throws SAXException JavaDoc {
711         // Register this prefix mapping
712
ArrayStack stack = (ArrayStack) namespaces.get(prefix);
713         if (stack == null) {
714             stack = new ArrayStack();
715             namespaces.put(prefix, stack);
716         }
717         stack.push(namespaceURI);
718
719         if ( elementNamespaces == null ) {
720             elementNamespaces = new HashMap JavaDoc();
721         }
722         elementNamespaces.put(prefix, namespaceURI);
723     }
724
725     /**
726      * Process notification that a namespace prefix is going out of scope.
727      *
728      * @param prefix Prefix that is going out of scope
729      *
730      * @exception SAXException if a parsing error is to be reported
731      */

732     public void endPrefixMapping(String JavaDoc prefix) throws SAXException JavaDoc {
733         // Deregister this prefix mapping
734
ArrayStack stack = (ArrayStack) namespaces.get(prefix);
735         if (stack == null) {
736             return;
737         }
738         try {
739             stack.pop();
740             if (stack.empty()) {
741                 namespaces.remove(prefix);
742             }
743         }
744         catch (EmptyStackException JavaDoc e) {
745             throw createSAXException("endPrefixMapping popped too many times");
746         }
747     }
748
749     /**
750      * Process notification of ignorable whitespace received from the body of
751      * an XML element.
752      *
753      * @param buffer The characters from the XML document
754      * @param start Starting offset into the buffer
755      * @param len Number of characters from the buffer
756      *
757      * @exception SAXException if a parsing error is to be reported
758      */

759     public void ignorableWhitespace(char buffer[], int start, int len)
760         throws SAXException JavaDoc {
761         ; // No processing required
762
}
763
764     /**
765      * Process notification of a processing instruction that was encountered.
766      *
767      * @param target The processing instruction target
768      * @param data The processing instruction data (if any)
769      *
770      * @exception SAXException if a parsing error is to be reported
771      */

772     public void processingInstruction(String JavaDoc target, String JavaDoc data)
773         throws SAXException JavaDoc {
774         ; // No processing is required
775
}
776
777     /**
778      * Set the document locator associated with our parser.
779      *
780      * @param locator The new locator
781      */

782     public void setDocumentLocator(Locator JavaDoc locator) {
783         this.locator = locator;
784     }
785
786     /**
787      * Process notification of a skipped entity.
788      *
789      * @param name Name of the skipped entity
790      *
791      * @exception SAXException if a parsing error is to be reported
792      */

793     public void skippedEntity(String JavaDoc name) throws SAXException JavaDoc {
794         ; // No processing required
795
}
796
797
798     // DTDHandler interface
799
//-------------------------------------------------------------------------
800

801     /**
802      * Receive notification of a notation declaration event.
803      *
804      * @param name The notation name
805      * @param publicId The public identifier (if any)
806      * @param systemId The system identifier (if any)
807      */

808     public void notationDecl(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId) {
809     }
810
811     /**
812      * Receive notification of an unparsed entity declaration event.
813      *
814      * @param name The unparsed entity name
815      * @param publicId The public identifier (if any)
816      * @param systemId The system identifier (if any)
817      * @param notation The name of the associated notation
818      */

819     public void unparsedEntityDecl(
820         String JavaDoc name,
821         String JavaDoc publicId,
822         String JavaDoc systemId,
823         String JavaDoc notation) {
824     }
825
826
827     // ErrorHandler interface
828
//-------------------------------------------------------------------------
829

830     /**
831      * Forward notification of a parsing error to the application supplied
832      * error handler, if any, otherwise throw a SAXException with the error.
833      *
834      * @param exception The error information
835      *
836      * @exception SAXException if a parsing exception occurs
837      */

838     public void error(SAXParseException exception) throws SAXException JavaDoc {
839         log.error(
840             "Parse Error at line "
841                 + exception.getLineNumber()
842                 + " column "
843                 + exception.getColumnNumber()
844                 + ": "
845                 + exception.getMessage(),
846             exception);
847         if (errorHandler != null) {
848             errorHandler.error(exception);
849         } else {
850             throw exception;
851         }
852     }
853
854     /**
855      * Forward notification of a fatal parsing error to the application
856      * supplied error handler, if any, otherwise throw a SAXException with the error.
857      *
858      * @param exception The fatal error information
859      *
860      * @exception SAXException if a parsing exception occurs
861      */

862     public void fatalError(SAXParseException exception) throws SAXException JavaDoc {
863         log.error(
864             "Parse Fatal Error at line "
865                 + exception.getLineNumber()
866                 + " column "
867                 + exception.getColumnNumber()
868                 + ": "
869                 + exception.getMessage(),
870             exception);
871         if (errorHandler != null) {
872             errorHandler.fatalError(exception);
873         } else {
874             throw exception;
875         }
876     }
877
878     /**
879      * Forward notification of a parse warning to the application supplied
880      * error handler (if any). Unlike XMLParser.error(SAXParseException) and
881      * XMLParser.fatalError(SAXParseException), this implementation will
882      * NOT throw a SAXException by default if no error handler is supplied.
883      *
884      * @param exception The warning information
885      *
886      * @exception SAXException if a parsing exception occurs
887      */

888     public void warning(SAXParseException exception) throws SAXException JavaDoc {
889         log.error(
890             "Parse Warning at line "
891                 + exception.getLineNumber()
892                 + " column "
893                 + exception.getColumnNumber()
894                 + ": "
895                 + exception.getMessage(),
896             exception);
897         if (errorHandler != null) {
898             errorHandler.warning(exception);
899         }
900     }
901
902     // Implementation methods
903
//-------------------------------------------------------------------------
904
/**
905      * If this object has not been configured then register the default
906      * namespaces
907      */

908     private void ensureConfigured() {
909         if (!configured) {
910             configure();
911             configured = true;
912         }
913     }
914
915     /**
916      * This method is called only once before parsing occurs
917      * which allows tag libraries to be registered and so forth
918      */

919     protected void configure() {
920         // load the properties file of libraries available
921
Properties JavaDoc properties = getJellyProperties();
922         for (Iterator JavaDoc iter = properties.entrySet().iterator(); iter.hasNext();) {
923             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
924             String JavaDoc uri = (String JavaDoc) entry.getKey();
925             String JavaDoc className = (String JavaDoc) entry.getValue();
926             String JavaDoc libraryURI = "jelly:" + uri;
927
928             // don't overload any Mock Tags already
929
if ( ! context.isTagLibraryRegistered(libraryURI) ) {
930                 context.registerTagLibrary(libraryURI, className);
931             }
932         }
933     }
934
935
936     /**
937      * A helper method which loads the static Jelly properties once on startup
938      */

939     protected synchronized Properties JavaDoc getJellyProperties() {
940         if (jellyProperties == null) {
941             jellyProperties = new Properties JavaDoc();
942
943             InputStream JavaDoc in = null;
944             URL JavaDoc url =
945                 getClassLoader().getResource("org/apache/commons/jelly/jelly.properties");
946             if (url != null) {
947                 log.debug("Loading Jelly default tag libraries from: " + url);
948                 try {
949                     in = url.openStream();
950                     jellyProperties .load(in);
951                 }
952                 catch (IOException JavaDoc e) {
953                     log.error("Could not load jelly properties from: " + url + ". Reason: " + e, e);
954                 }
955                 finally {
956                     try {
957                         in.close();
958                     }
959                     catch (Exception JavaDoc e) {
960                         if (log.isDebugEnabled()) log.debug("error closing jelly.properties", e);
961                     }
962                 }
963             }
964         }
965         return jellyProperties;
966     }
967
968     /**
969      * Factory method to create new Tag script for the given namespaceURI and name or
970      * return null if this is not a custom Tag.
971      */

972     protected TagScript createTag(
973         String JavaDoc namespaceURI,
974         String JavaDoc localName,
975         Attributes JavaDoc list)
976         throws SAXException JavaDoc {
977         try {
978             // use the URI to load a taglib
979
TagLibrary taglib = context.getTagLibrary(namespaceURI);
980             if (taglib == null) {
981                 if (namespaceURI != null && namespaceURI.startsWith("jelly:")) {
982                     String JavaDoc uri = namespaceURI.substring(6);
983                     // try to find the class on the claspath
984
try {
985                         Class JavaDoc taglibClass = getClassLoader().loadClass(uri);
986                         taglib = (TagLibrary) taglibClass.newInstance();
987                         context.registerTagLibrary(namespaceURI, taglib);
988                     }
989                     catch (ClassNotFoundException JavaDoc e) {
990                         throw createSAXException("Could not load class: " + uri + " so taglib instantiation failed", e);
991                     }
992                     catch (IllegalAccessException JavaDoc e) {
993                         throw createSAXException("Constructor for class is not accessible: " + uri + " so taglib instantiation failed",e);
994                     }
995                     catch (InstantiationException JavaDoc e) {
996                         throw createSAXException("Class could not be instantiated: " + uri + " so taglib instantiation failed",e);
997                     }
998                     catch (ClassCastException JavaDoc e) {
999                         throw createSAXException("Class is not a TagLibrary: " + uri + " so taglib instantiation failed",e);
1000                    }
1001                }
1002            }
1003            if (taglib != null) {
1004                TagScript script = taglib.createTagScript(localName, list);
1005                if ( script != null ) {
1006                    configureTagScript(script);
1007
1008                    // clone the attributes to keep them around after this parse
1009
script.setSaxAttributes(new AttributesImpl JavaDoc(list));
1010
1011                    // now iterate through through the expressions
1012
int size = list.getLength();
1013                    for (int i = 0; i < size; i++) {
1014                        String JavaDoc attributeName = list.getLocalName(i);
1015                        String JavaDoc attributeValue = list.getValue(i);
1016                        Expression expression =
1017                            taglib.createExpression(
1018                                getExpressionFactory(),
1019                                script,
1020                                attributeName,
1021                                attributeValue);
1022                        if (expression == null) {
1023                            expression = createConstantExpression(localName, attributeName, attributeValue);
1024                        }
1025                        script.addAttribute(attributeName, expression);
1026                    }
1027                }
1028                return script;
1029            }
1030            return null;
1031        }
1032        catch (Exception JavaDoc e) {
1033            log.warn(
1034                "Could not create taglib or URI: " + namespaceURI + " tag name: " + localName,
1035                e);
1036            throw createSAXException(e);
1037        }
1038    }
1039
1040
1041    /**
1042     * Factory method to create a static Tag that represents some static content.
1043     */

1044    protected TagScript createStaticTag(
1045        final String JavaDoc namespaceURI,
1046        final String JavaDoc localName,
1047        final String JavaDoc qName,
1048        Attributes JavaDoc list)
1049        throws SAXException JavaDoc {
1050        try {
1051            StaticTag tag = new StaticTag( namespaceURI, localName, qName );
1052            StaticTagScript script = new StaticTagScript(
1053                new TagFactory() {
1054                    public Tag createTag(String JavaDoc name, Attributes JavaDoc attributes) {
1055                        return new StaticTag( namespaceURI, localName, qName );
1056                    }
1057                }
1058            );
1059            configureTagScript(script);
1060
1061            // now iterate through through the expressions
1062
int size = list.getLength();
1063            for (int i = 0; i < size; i++) {
1064                String JavaDoc attributeValue = list.getValue(i);
1065                Expression expression = CompositeExpression.parse(
1066                        attributeValue, getExpressionFactory()
1067                    );
1068                String JavaDoc attrQName = list.getQName(i);
1069                int p = attrQName.indexOf(':');
1070                String JavaDoc prefix = p>=0 ?
1071                        attrQName.substring(0,p):
1072                        "";
1073                script.addAttribute(list.getLocalName(i),
1074                        prefix, list.getURI(i), expression);
1075            }
1076            return script;
1077        }
1078        catch (Exception JavaDoc e) {
1079            log.warn(
1080                "Could not create static tag for URI: "
1081                    + namespaceURI
1082                    + " tag name: "
1083                    + localName,
1084                e);
1085            throw createSAXException(e);
1086        }
1087    }
1088
1089
1090    /**
1091     * Configure a newly created TagScript instance before any Expressions are created
1092     *
1093     * @param aTagScript
1094     */

1095    protected void configureTagScript(TagScript aTagScript) {
1096        // set parent relationship...
1097
aTagScript.setParent(this.tagScript);
1098
1099        // set the namespace Map
1100
if ( elementNamespaces != null ) {
1101            aTagScript.setTagNamespacesMap( elementNamespaces );
1102            elementNamespaces = null;
1103        }
1104    }
1105
1106    /**
1107     * Adds the text to the current script block parsing any embedded
1108     * expressions inot ExpressionScript objects.
1109     */

1110    protected void addTextScript(String JavaDoc text) throws JellyException {
1111        Expression expression =
1112            CompositeExpression.parse(text, getExpressionFactory());
1113
1114        addExpressionScript(script, expression);
1115    }
1116
1117
1118    /**
1119     * Adds the given Expression object to the current Script.
1120     */

1121    protected void addExpressionScript(ScriptBlock script, Expression expression) {
1122        if ( expression instanceof ConstantExpression ) {
1123            ConstantExpression constantExpression
1124                = (ConstantExpression) expression;
1125            Object JavaDoc value = constantExpression.getValue();
1126            if ( value != null ) {
1127                script.addScript(new TextScript( value.toString() ));
1128            }
1129        }
1130        else
1131        if ( expression instanceof CompositeExpression ) {
1132            CompositeTextScriptBlock newBlock = new CompositeTextScriptBlock();
1133            script.addScript(newBlock);
1134
1135            CompositeExpression compositeExpression
1136                = (CompositeExpression) expression;
1137            Iterator JavaDoc iter = compositeExpression.getExpressions().iterator();
1138            while (iter.hasNext()) {
1139                addExpressionScript( newBlock, (Expression) iter.next() );
1140            }
1141        }
1142        else {
1143            script.addScript(new ExpressionScript(expression));
1144        }
1145    }
1146
1147    protected Expression createConstantExpression(
1148        String JavaDoc tagName,
1149        String JavaDoc attributeName,
1150        String JavaDoc attributeValue) {
1151        return new ConstantExpression(attributeValue);
1152    }
1153
1154    protected ExpressionFactory createExpressionFactory() {
1155        return new JexlExpressionFactory();
1156    }
1157
1158    /**
1159     * @return the current context URI as a String or null if there is no
1160     * current context defined on the JellyContext
1161     */

1162    protected String JavaDoc getCurrentURI() {
1163        URL JavaDoc url = this.getContext().getCurrentURL();
1164        return (url != null) ? url.toString() : null;
1165    }
1166
1167    /**
1168     * Create a SAX exception which also understands about the location in
1169     * the file where the exception occurs
1170     *
1171     * @return the new exception
1172     */

1173    protected SAXException JavaDoc createSAXException(String JavaDoc message, Exception JavaDoc e) {
1174        log.warn("Underlying exception: " + e);
1175        if (locator != null) {
1176            String JavaDoc error =
1177                "Error at ("
1178                    + locator.getLineNumber()
1179                    + ", "
1180                    + locator.getColumnNumber()
1181                    + ") of " + locator.getSystemId()
1182                    + " : "
1183                    + message;
1184            if (e != null) {
1185                return new SAXParseException(error, locator, e);
1186            }
1187            else {
1188                return new SAXParseException(error, locator);
1189            }
1190        }
1191        log.error("No Locator!");
1192        if (e != null) {
1193            return new SAXException JavaDoc(message, e);
1194        }
1195        else {
1196            return new SAXException JavaDoc(message);
1197        }
1198    }
1199
1200    /**
1201     * Create a SAX exception which also understands about the location in
1202     * the digester file where the exception occurs
1203     *
1204     * @return the new exception
1205     */

1206    protected SAXException JavaDoc createSAXException(Exception JavaDoc e) {
1207        return createSAXException(e.getMessage(), e);
1208    }
1209    /**
1210     * Create a SAX exception which also understands about the location in
1211     * the digester file where the exception occurs
1212     *
1213     * @return the new exception
1214     */

1215    protected SAXException JavaDoc createSAXException(String JavaDoc message) {
1216        return createSAXException(message, null);
1217    }
1218}
1219
Popular Tags