View Javadoc

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.tags.betwixt;
17  
18  import java.beans.IntrospectionException;
19  import java.io.IOException;
20  import java.net.URL;
21  
22  import org.apache.commons.betwixt.XMLIntrospector;
23  import org.apache.commons.betwixt.io.BeanReader;
24  
25  import org.apache.commons.jelly.JellyTagException;
26  import org.apache.commons.jelly.MissingAttributeException;
27  import org.apache.commons.jelly.TagSupport;
28  import org.apache.commons.jelly.XMLOutput;
29  import org.apache.commons.jelly.util.ClassLoaderUtils;
30  
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  import org.xml.sax.SAXException;
35  
36  /***
37   * Parses some XML specified via the given URI (which can be relative or an absolute URL) and outputs the
38   * parsed object. Typically this tag is customized by setting the introspector attribute or nesting a child
39   * introspector tag inside it.</p>
40   *
41   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
42   * @version $Revision: 155420 $
43   */
44  public class ParseTag extends TagSupport {
45  
46      /*** The Log to which logging calls will be made. */
47      private static final Log log = LogFactory.getLog(ParseTag.class);
48  
49      /*** the BeanReader used to parse the XML */
50      private BeanReader reader = new BeanReader();
51  
52      private String uri;
53      private String var;
54      private String rootClass;
55      private String path;
56      private XMLIntrospector introspector;
57      private boolean useContextClassLoader;
58      private ClassLoader classLoader;
59  
60  
61      public ParseTag() {
62      }
63  
64      // Tag interface
65      //-------------------------------------------------------------------------
66      public void doTag(final XMLOutput output) throws MissingAttributeException, JellyTagException {
67          if ( var == null ) {
68              throw new MissingAttributeException( "var" );
69          }
70          if ( rootClass == null ) {
71              throw new MissingAttributeException( "rootClass" );
72          }
73  
74          reader.setXMLIntrospector(getIntrospector());
75  
76          Class theClass = null;
77          try {
78              theClass = getClassLoader().loadClass( rootClass );
79          }
80          catch (Exception e) {
81              throw new JellyTagException( "Could not load class called: " + rootClass, e );
82          }
83  
84          if ( theClass == null ) {
85              throw new JellyTagException( "Could not load class called: " + rootClass );
86          }
87  
88          try {
89              if ( path != null ) {
90                  reader.registerBeanClass( path, theClass );
91              }
92              else {
93                  reader.registerBeanClass( theClass );
94              }
95          }
96          catch (IntrospectionException e) {
97              throw new JellyTagException(e);
98          }
99  
100         Object value = null;
101         if ( uri != null ) {
102             invokeBody(output);
103 
104             try {
105                 URL url = context.getResource( uri );
106                 value = reader.parse( url.toString() );
107             } catch (IOException e) {
108                 throw new JellyTagException(e);
109             } catch (SAXException e) {
110                 throw new JellyTagException(e);
111             }
112         }
113         else {
114 
115             // invoke the body and pass that into the reader
116             XMLOutput newOutput = new XMLOutput( reader );
117 
118             invokeBody(newOutput);
119 
120             value = reader.getRoot();
121         }
122         context.setVariable( var, value );
123     }
124 
125     // Properties
126     //-------------------------------------------------------------------------
127 
128     /***
129      * @return the introspector to be used, lazily creating one if required.
130      */
131     public XMLIntrospector getIntrospector() {
132         if (introspector == null) {
133             introspector = new XMLIntrospector();
134         }
135         return introspector;
136     }
137     /***
138      * Sets the Betwixt XMLIntrospector instance used to define the metadata for how a
139      * bean should appear as XML.
140      */
141     public void setIntrospector(XMLIntrospector introspector) {
142         this.introspector = introspector;
143     }
144 
145     /***
146      * Sets the URI from which XML is parsed. This can be relative to this Jelly script, use
147      * an absolute URI or a full URL
148      */
149     public void setUri(String uri) {
150         this.uri = uri;
151     }
152 
153     /***
154      * Sets the variable name to output with the result of the XML parse.
155      */
156     public void setVar(String var) {
157         this.var = var;
158     }
159 
160     /***
161      * Sets the name of the root class to use for parsing the XML
162      */
163     public void setRootClass(String rootClass) {
164         this.rootClass = rootClass;
165     }
166 
167     /***
168      * Sets the path that the root class should be bound to.
169      * This is optional and often unnecessary though can be used to ignore some wrapping
170      * elements, such as the &lt;rss&gt; element in the RSS unit test.
171      */
172     public void setPath(String path) {
173         this.path = path;
174     }
175 
176 
177     /***
178      * Sets whether or not the current threads's context class loader
179      * should be used to load the bean classes or not.
180      * This can be useful if running inside a web application or inside some
181      * application server.
182      */
183     public void setUseContextClassLoader(boolean useContextClassLoader) {
184         this.useContextClassLoader = useContextClassLoader;
185     }
186 
187     /***
188      * Sets the ClassLoader to be used to load bean classes from.
189      * If this is not specified then either the ClassLoader used to load this tag library
190      * is used or, if the 'useContextClassLoader' property is true, then the
191      * current threads context class loader is used instead.
192      */
193     public void setClassLoader(ClassLoader classLoader) {
194         this.classLoader = classLoader;
195     }
196 
197 
198     // Implementation methods
199     //-------------------------------------------------------------------------
200 
201     /***
202      * @return the ClassLoader to be used to load bean classes.
203      */
204     protected ClassLoader getClassLoader() {
205         return ClassLoaderUtils.getClassLoader(classLoader, useContextClassLoader, getClass());
206     }
207 }