1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jelly.tags.bean;
18
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.util.Collection;
22
23 import org.apache.commons.beanutils.BeanUtils;
24 import org.apache.commons.beanutils.MethodUtils;
25 import org.apache.commons.jelly.JellyTagException;
26 import org.apache.commons.jelly.Tag;
27 import org.apache.commons.jelly.impl.BeanSource;
28 import org.apache.commons.jelly.impl.CollectionTag;
29 import org.apache.commons.jelly.tags.core.UseBeanTag;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32
33
34 /***
35 * Creates a bean for the given tag which is then either output as a variable
36 * or can be added to a parent tag.
37 *
38 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
39 * @author Christian Sell
40 * @version $Revision: 155420 $
41 */
42 public class BeanTag extends UseBeanTag {
43
44 /*** The Log to which logging calls will be made. */
45 private static final Log log = LogFactory.getLog(BeanTag.class);
46
47 protected static final Object[] EMPTY_ARGUMENTS = {};
48
49 /*** the name of the property to create */
50 private String tagName;
51
52 /*** the name of the adder method */
53 protected String addMethodName;
54
55 /*** if present this is used to call a doit method when the bean is constructed */
56 private Method invokeMethod;
57
58
59 public BeanTag() {
60 this(null, "bean", null);
61 }
62
63 public BeanTag(Class defaultClass, String tagName) {
64 this(defaultClass, tagName, null);
65 }
66
67 public BeanTag(Class defaultClass, String tagName, Method invokeMethod) {
68 super(defaultClass);
69 this.tagName = tagName;
70 this.invokeMethod = invokeMethod;
71
72 if (tagName.length() > 0) {
73 addMethodName = "add"
74 + tagName.substring(0,1).toUpperCase()
75 + tagName.substring(1);
76 }
77 }
78
79 /***
80 * @return the local name of the XML tag to which this tag is bound
81 */
82 public String getTagName() {
83 return tagName;
84 }
85
86 /***
87 * Output the tag as a named variable. If the parent bean has an adder or setter
88 * method then invoke that to register this bean with its parent.
89 */
90 protected void processBean(String var, Object bean) throws JellyTagException {
91 if (var != null) {
92 context.setVariable(var, bean);
93 }
94
95
96 if (bean != null) {
97 Tag parent = this;
98
99 while (true) {
100 parent = parent.getParent();
101 if (parent == null) {
102 break;
103 }
104
105 if (parent instanceof BeanSource) {
106 BeanSource source = (BeanSource) parent;
107 Object parentObject = source.getBean();
108 if (parentObject != null) {
109 if (parentObject instanceof Collection) {
110 Collection collection = (Collection) parentObject;
111 collection.add(bean);
112 }
113 else {
114
115 Method method = findAddMethod(parentObject.getClass(), bean.getClass());
116 if (method != null) {
117 Object[] args = { bean };
118 try {
119 method.invoke(parentObject, args);
120 }
121 catch (Exception e) {
122 throw new JellyTagException( "failed to invoke method: " + method + " on bean: " + parentObject + " reason: " + e, e );
123 }
124 }
125 else {
126 try {
127 BeanUtils.setProperty(parentObject, tagName, bean);
128 } catch (IllegalAccessException e) {
129 throw new JellyTagException(e);
130 } catch (InvocationTargetException e) {
131 throw new JellyTagException(e);
132 }
133 }
134 }
135 }
136 else {
137 log.warn("Cannot process null bean for tag: " + parent);
138 }
139 }
140 else if (parent instanceof CollectionTag) {
141 CollectionTag tag = (CollectionTag) parent;
142 tag.addItem(bean);
143 }
144 else {
145 continue;
146 }
147 break;
148 }
149
150 if (invokeMethod != null) {
151 Object[] args = { bean };
152 try {
153 invokeMethod.invoke(bean, EMPTY_ARGUMENTS);
154 }
155 catch (Exception e) {
156 throw new JellyTagException( "failed to invoke method: " + invokeMethod + " on bean: " + bean + " reason: " + e, e );
157 }
158 }
159 else {
160 if (parent == null && var == null) {
161
162 log.warn( "Could not add bean to parent for bean: " + bean );
163 }
164 }
165 }
166 }
167
168 /***
169 * Finds the Method to add the new bean
170 */
171 protected Method findAddMethod(Class beanClass, Class valueClass) {
172 if (addMethodName == null) {
173 return null;
174 }
175 Class[] argTypes = { valueClass };
176 return MethodUtils.getAccessibleMethod(
177 beanClass, addMethodName, argTypes
178 );
179 }
180
181
182 /***
183 * @return the parent bean object
184 */
185 protected Object getParentObject() throws JellyTagException {
186 BeanSource tag = (BeanSource) findAncestorWithClass(BeanSource.class);
187 if (tag != null) {
188 return tag.getBean();
189 }
190 return null;
191 }
192 }