1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
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
116 XMLOutput newOutput = new XMLOutput( reader );
117
118 invokeBody(newOutput);
119
120 value = reader.getRoot();
121 }
122 context.setVariable( var, value );
123 }
124
125
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 <rss> 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
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 }