1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.jameleon;
21
22 import java.lang.reflect.Field;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import net.sf.jameleon.bean.Attribute;
31 import net.sf.jameleon.bean.FunctionalPoint;
32 import net.sf.jameleon.exception.JameleonException;
33 import net.sf.jameleon.exception.JameleonScriptException;
34 import net.sf.jameleon.function.Attributable;
35 import net.sf.jameleon.function.AttributeBroker;
36 import net.sf.jameleon.function.ContextHelper;
37 import net.sf.jameleon.util.JameleonUtility;
38
39 import org.apache.commons.beanutils.BeanUtils;
40 import org.apache.commons.jelly.DynaTag;
41 import org.apache.commons.jelly.JellyTagException;
42
43 /***
44 * <p><code>JameleonTagSupport</code> is an implementation of DynaTag. This tag
45 * throws the variable name as the XML attribute into the context. It then
46 * attempts to call to corresponding set method. There is currently no checking
47 * on whether the set method was called or not. If it's there, then it gets
48 * called. Calling the set method is mostly for backward compatability. However,
49 * it can be used for set methods that need to do more than put the variable in the
50 * context.</p>
51 * <p>
52 * Currently, this class is only used by FunctionTag. It was intended to be the base class for all
53 * Jameleon tags.
54 * </p>
55 */
56 public abstract class JameleonTagSupport extends LocationAwareTagSupport implements DynaTag, Attributable {
57
58 /***
59 * A map of class attributes and their corresponding types.
60 */
61 protected Map attributes = null;
62 /***
63 * A list of variable names that were stored in the context.
64 */
65 protected List contextVars = new LinkedList();
66 /***
67 * Used to transfer context variables to instance variables.
68 */
69 protected AttributeBroker broker;
70 /***
71 * Represents this tag's attributes
72 */
73 protected FunctionalPoint fp;
74
75 protected List unsupportedAttributes = new LinkedList();
76
77 public JameleonTagSupport(){
78 super();
79 broker = new AttributeBroker(this);
80 fp = loadFunctionalPoint();
81
82 broker.setUp();
83 }
84
85 public FunctionalPoint loadFunctionalPoint(){
86 FunctionalPoint functionalPoint = null;
87 try{
88 functionalPoint = JameleonUtility.loadFunctionalPoint(this.getClass().getName(), this);
89 }catch(JameleonScriptException jse){
90 throw new JameleonScriptException(jse.getMessage(), this);
91 }
92 return functionalPoint;
93 }
94
95 public List getUnsupportedAttributes(){
96 return unsupportedAttributes;
97 }
98
99 protected void testForUnsupportedAttributesCaught(){
100 if (unsupportedAttributes.size() > 0) {
101 Iterator it = unsupportedAttributes.iterator();
102 String msg = "The following attributes are not supported by this tag:\n";
103 while (it.hasNext()) {
104 msg += "'"+it.next()+"'";
105 if (it.hasNext()) {
106 msg += ", ";
107 }
108 }
109 msg += ".\n This could also be that Jameleon could not find the tag's corresponding .dat file\n"+
110 "that is generated when the tags are registered and should be in the CLASSPATH.\n\n";
111 throw new JameleonScriptException(msg, this);
112 }
113 }
114
115 /***
116 * Sets an attribute value of this tag before the tag is invoked
117 */
118 public void setAttribute(String name, Object value) {
119 if (fp != null) {
120 Attribute attr = fp.getAttribute(name);
121 if (attr != null) {
122 if (attr.isInstanceVariable()){
123 if (!attr.isContextVariable() ||
124 name.equals(attr.getName()) ) {
125 try{
126 broker.setConsumerAttribute(attr, value);
127 }catch(JameleonException je){
128 throw new JameleonScriptException(je, this);
129 }
130 attr.setValue(value);
131 } else if (attr.isContextVariable()){
132 setVariableInContext(attr.getContextName(), value);
133 }
134 }else{
135 try{
136
137
138 BeanUtils.copyProperty(this, name, value);
139
140
141 fp.getAttributes().put(name, attr);
142 attr.setValue(value);
143 }catch(Exception e){
144 throw new JameleonScriptException(e, this);
145 }
146 }
147 }else{
148 unsupportedAttributes.add(name);
149 }
150 }else{
151 unsupportedAttributes.add(name);
152 }
153 }
154
155 protected void setVariableInContext(String name, Object value){
156 context.setVariable(name,value);
157 contextVars.add(name);
158 }
159
160 protected void cleanVariablesInContext(){
161 ContextHelper.removeVariables(context, contextVars);
162 }
163
164 /***
165 * Helper method which allows derived tags to access the attributes
166 * associated with this tag
167 * @return the context of the tag.
168 */
169 protected Map getAttributes() {
170 return context.getVariables();
171 }
172
173 public AttributeBroker getAttributeBroker(){
174 return broker;
175 }
176
177 /***
178 * Simply returns the context for this tag
179 */
180 protected Map createAttributes() {
181 return context.getVariables();
182 }
183
184 /***
185 * Gets the attributes or fields of the tag
186 */
187 protected Map getClassAttributes(){
188 if (attributes == null) {
189 attributes = new HashMap();
190 Class clzz = this.getClass();
191 do {
192 Field[] fields = clzz.getDeclaredFields();
193 for (int i = 0; i < fields.length; i++) {
194 attributes.put(fields[i].getName(),fields[i].getType());
195 }
196 clzz = clzz.getSuperclass();
197 }while(!clzz.equals(JameleonTagSupport.class));
198 }
199 return attributes;
200 }
201
202 /***
203 * @return the type of the given attribute. If we can't figure out
204 * the type of variable, simply return Object.class
205 * Required for dyna tag support.
206 */
207 public Class getAttributeType(String name) throws JellyTagException {
208 getClassAttributes();
209 Class clzz = Object.class;
210 if (attributes.containsKey(name)) {
211 clzz = (Class)attributes.get(name);
212 }
213 return clzz;
214 }
215
216 protected void resetFunctionalPoint(){
217 cleanVariablesInContext();
218 Map attrs = fp.getAttributes();
219 Iterator it = attrs.keySet().iterator();
220 String key;
221 Attribute attr;
222 Field f = null;
223 while (it.hasNext()) {
224 key = (String)it.next();
225 attr = (Attribute)attrs.get(key);
226 if (attr.isInstanceVariable()) {
227 f = broker.getConsumerField(attr);
228 if (f.getType().isPrimitive()) {
229 broker.setConsumerAttributeAsPrimitive(f, attr.getDefaultValue());
230 }else{
231 broker.setConsumerAttributeAsObject(f, attr.getDefaultValue());
232 }
233 }else if (attr.getDefaultValue() != null){
234 try{
235
236
237 BeanUtils.copyProperty(this, key, attr.getDefaultValue());
238 }catch(Exception e){
239 throw new JameleonScriptException(e, this);
240 }
241 }
242 attr.setValue(null);
243 }
244 }
245
246 public FunctionalPoint getFunctionalPoint(){
247 return fp;
248 }
249
250
251 public void describeAttributes(AttributeBroker broker) {
252 if (fp != null) {
253 Map attrs = fp.getAttributes();
254 if (attrs != null) {
255 Set keys = attrs.keySet();
256 if (keys != null) {
257 Iterator it = keys.iterator();
258 while (it != null && it.hasNext()) {
259 broker.registerAttribute((Attribute)fp.getAttributes().get(it.next()));
260 }
261 }
262 }
263 }
264 }
265
266 }