View Javadoc

1   /*
2       Jameleon - An automation testing tool..
3       Copyright (C) 2003-2006 Christian W. Hargraves (engrean@hotmail.com)
4       
5       This library is free software; you can redistribute it and/or
6       modify it under the terms of the GNU Lesser General Public
7       License as published by the Free Software Foundation; either
8       version 2.1 of the License, or (at your option) any later version.
9   
10      This library is distributed in the hope that it will be useful,
11      but WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13      Lesser General Public License for more details.
14  
15      You should have received a copy of the GNU Lesser General Public
16      License along with this library; if not, write to the Free Software
17      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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          //This calls describeAttributes()
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                         //There is currently no reasonable way through the commons beanutils API to know whether the method was set or not.
137                         //So I have to assume it was indeed set.
138                         BeanUtils.copyProperty(this, name, value);
139 
140                         //This won't get set because it may not set a context variable
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                     //There is currently no reasonable way through the commons beanutils API to know whether the method was set or.
236                     //So I have to assume it was indeed set.
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     // -------------- Begin Attributable methods
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 }