KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jelly > impl > DynamicBeanTag


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.impl;
17
18 import java.lang.reflect.InvocationTargetException JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23 import java.util.Set JavaDoc;
24
25 import org.apache.commons.beanutils.ConvertingWrapDynaBean;
26 import org.apache.commons.collections.BeanMap;
27 import org.apache.commons.jelly.DynaBeanTagSupport;
28 import org.apache.commons.jelly.JellyTagException;
29 import org.apache.commons.jelly.MissingAttributeException;
30 import org.apache.commons.jelly.Tag;
31 import org.apache.commons.jelly.XMLOutput;
32 import org.apache.commons.jelly.expression.Expression;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35
36 /**
37  * This tag is bound onto a Java Bean class. When the tag is invoked a bean will be created
38  * using the tags attributes.
39  * The bean may also have an invoke method called invoke(), run(), execute() or some such method
40  * which will be invoked after the bean has been configured.</p>
41  *
42  * @author <a HREF="mailto:jstrachan@apache.org">James Strachan</a>
43  * @author <a HREF="mailto:jason@zenplex.com">Jason van Zyl</a>
44  * @version $Revision: 155420 $
45  */

46 public class DynamicBeanTag extends DynaBeanTagSupport implements BeanSource {
47
48     /** The Log to which logging calls will be made. */
49     private static final Log log = LogFactory.getLog(DynamicBeanTag.class);
50
51     /** Empty arguments for Method.invoke() */
52     private static final Object JavaDoc[] emptyArgs = {};
53
54     /** the bean class */
55     private Class JavaDoc beanClass;
56
57     /** the current bean instance */
58     private Object JavaDoc bean;
59
60     /** the method to invoke on the bean */
61     private Method JavaDoc method;
62
63     /**
64      * the tag attribute name that is used to declare the name
65      * of the variable to export after running this tag
66      */

67     private String JavaDoc variableNameAttribute;
68
69     /** the current variable name that the bean should be exported as */
70     private String JavaDoc var;
71
72     /** the set of attribute names we've already set */
73     private Set JavaDoc setAttributesSet = new HashSet JavaDoc();
74
75     /** the attribute definitions */
76     private Map JavaDoc attributes;
77
78     /**
79      *
80      * @param beanClass Class of the bean that will receive the setter events
81      * @param attributes
82      * @param variableNameAttribute
83      * @param method method of the Bean to invoke after the attributes have been set. Can be null.
84      */

85     public DynamicBeanTag(Class JavaDoc beanClass, Map JavaDoc attributes, String JavaDoc variableNameAttribute, Method JavaDoc method) {
86         this.beanClass = beanClass;
87         this.method = method;
88         this.attributes = attributes;
89         this.variableNameAttribute = variableNameAttribute;
90     }
91
92     public void beforeSetAttributes() throws JellyTagException {
93         // create a new dynabean before the attributes are set
94
try {
95             bean = beanClass.newInstance();
96             setDynaBean( new ConvertingWrapDynaBean( bean ) );
97         } catch (InstantiationException JavaDoc e) {
98             throw new JellyTagException("Could not instantiate dynabean",e);
99         } catch (IllegalAccessException JavaDoc e) {
100             throw new JellyTagException("Could not instantiate dynabean",e);
101         }
102
103         setAttributesSet.clear();
104     }
105
106     public void setAttribute(String JavaDoc name, Object JavaDoc value) throws JellyTagException {
107         boolean isVariableName = false;
108         if (variableNameAttribute != null ) {
109             if ( variableNameAttribute.equals( name ) ) {
110                 if (value == null) {
111                     var = null;
112                 }
113                 else {
114                     var = value.toString();
115                 }
116                 isVariableName = true;
117             }
118         }
119         if (! isVariableName) {
120
121             // #### strictly speaking we could
122
// know what attributes are specified at compile time
123
// so this dynamic set is unnecessary
124
setAttributesSet.add(name);
125
126             // we could maybe implement attribute specific validation here
127

128             super.setAttribute(name, value);
129         }
130     }
131
132     // Tag interface
133
//-------------------------------------------------------------------------
134
public void doTag(XMLOutput output) throws JellyTagException {
135
136         // lets find any attributes that are not set and
137
for ( Iterator JavaDoc iter = attributes.values().iterator(); iter.hasNext(); ) {
138             Attribute attribute = (Attribute) iter.next();
139             String JavaDoc name = attribute.getName();
140             if ( ! setAttributesSet.contains( name ) ) {
141                 if ( attribute.isRequired() ) {
142                     throw new MissingAttributeException(name);
143                 }
144                 // lets get the default value
145
Object JavaDoc value = null;
146                 Expression expression = attribute.getDefaultValue();
147                 if ( expression != null ) {
148                     value = expression.evaluate(context);
149                 }
150
151                 // only set non-null values?
152
if ( value != null ) {
153                     super.setAttribute(name, value);
154                 }
155             }
156         }
157
158         // If the dynamic bean is itself a tag, let it execute itself
159
if (bean instanceof Tag)
160         {
161             Tag tag = (Tag) bean;
162             tag.setBody(getBody());
163             tag.setContext(getContext());
164             tag.setParent(getParent());
165             ((Tag) bean).doTag(output);
166
167             return;
168         }
169
170         invokeBody(output);
171
172         // export the bean if required
173
if ( var != null ) {
174             context.setVariable(var, bean);
175         }
176
177         // now, I may invoke the 'execute' method if I have one
178
if ( method != null ) {
179             try {
180                 method.invoke( bean, emptyArgs );
181             }
182             catch (IllegalAccessException JavaDoc e) {
183                 methodInvocationException(bean, method, e);
184             }
185             catch (IllegalArgumentException JavaDoc e) {
186                 methodInvocationException(bean, method, e);
187             }
188             catch (InvocationTargetException JavaDoc e) {
189                 // methodInvocationError(bean, method, e);
190

191                 Throwable JavaDoc inner = e.getTargetException();
192
193                 throw new JellyTagException(inner);
194
195             }
196         }
197     }
198
199     /**
200      * Report the state of the bean when method invocation fails
201      * so that the user can determine any problems that might
202      * be occuring while using dynamic jelly beans.
203      *
204      * @param bean Bean on which <code>method</code was invoked
205      * @param method Method that was invoked
206      * @param e Exception throw when <code>method</code> was invoked
207      */

208     private void methodInvocationException(Object JavaDoc bean, Method JavaDoc method, Exception JavaDoc e) throws JellyTagException {
209         log.error("Could not invoke " + method, e);
210         BeanMap beanMap = new BeanMap(bean);
211
212         log.error("Bean properties:");
213         for (Iterator JavaDoc i = beanMap.keySet().iterator(); i.hasNext();) {
214             String JavaDoc property = (String JavaDoc) i.next();
215             Object JavaDoc value = beanMap.get(property);
216             log.error(property + " -> " + value);
217         }
218
219         log.error(beanMap);
220         throw new JellyTagException(e);
221     }
222
223     // Properties
224
//-------------------------------------------------------------------------
225
/**
226      * @return the bean that has just been created
227      */

228     public Object JavaDoc getBean() {
229         return bean;
230     }
231 }
232
Popular Tags