View Javadoc

1   //$Id: CallCreatorAction.java 250 2006-08-25 21:30:26Z jg_hamburg $
2   /********************************************************************************
3    * DDTUnit, a Datadriven Approach to Unit- and Moduletesting
4    * Copyright (c) 2004, Joerg and Kai Gellien
5    * All rights reserved.
6    *
7    * The Software is provided under the terms of the Common Public License 1.0
8    * as provided with the distribution of DDTUnit in the file cpl-v10.html.
9    * Redistribution and use in source and binary forms, with or without
10   * modification, are permitted provided that the following conditions
11   * are met:
12   *
13   *     + Redistributions of source code must retain the above copyright
14   *       notice, this list of conditions and the following disclaimer.
15   *
16   *     + Redistributions in binary form must reproduce the above
17   *       copyright notice, this list of conditions and the following
18   *       disclaimer in the documentation and/or other materials provided
19   *       with the distribution.
20   *
21   *     + Neither the id of the authors or DDTUnit, nor the
22   *       names of its contributors may be used to endorse or promote
23   *       products derived from this software without specific prior
24   *       written permission.
25   *
26   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
30   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37   ********************************************************************************/
38  package junitx.ddtunit.data.processing;
39  
40  import java.lang.reflect.Constructor;
41  import java.lang.reflect.Method;
42  import java.lang.reflect.Modifier;
43  import java.util.HashMap;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Vector;
47  
48  import junitx.ddtunit.DDTException;
49  import junitx.ddtunit.data.DDTTestDataException;
50  import junitx.ddtunit.data.TypedObject;
51  import junitx.ddtunit.util.ClassAnalyser;
52  import junitx.ddtunit.util.PrivilegedAccessor;
53  
54  /**
55   * This class contains object state and other information to create object from
56   * SAX event stream.
57   * 
58   * @author jg
59   */
60  public class CallCreatorAction extends ActionBase {
61      /**
62       * 
63       * Constructor used as standard constructor to instanciate actions of this
64       * type
65       * 
66       * @param attrMap
67       */
68      public CallCreatorAction(Map<String, String> attrMap) {
69          super(attrMap);
70      }
71  
72      /*
73       * (non-Javadoc)
74       * 
75       * @see junitx.ddtunit.parser.ActionBase#process()
76       */
77      public IAction process() {
78          log.debug("process CallCreator - START");
79          if (!this.successorProcessed) {
80              processNoSuccessor();
81          }
82          IAction rootAction = this.getPrevious();
83          if (rootAction != null) {
84              String hintValue = rootAction.getHint();
85  
86              if (HintTypes.COLLECTION.equals(hintValue)) {
87                  rootAction.processSuccessor(this);
88              } else if (HintTypes.MAP.equals(hintValue)) {
89                  rootAction.processSuccessor(this);
90              } else if (HintTypes.ATTRLIST.equals(hintValue)) {
91                  rootAction.processSuccessor(this);
92              } else if (HintTypes.FIELDS.equals(hintValue)) {
93                  rootAction.processSuccessor(this);
94              } else if (HintTypes.CONSTRUCTOR.equals(hintValue)
95                      || HintTypes.CALL.equals(hintValue)) {
96                  rootAction.processSuccessor(this);
97              } else if (HintTypes.BEAN.equals(hintValue)) {
98                  rootAction.processSuccessor(this);
99              } else if (HintTypes.ARRAY.equals(hintValue)) {
100                 rootAction.processSuccessor(this);
101             } else if (HintTypes.INTERNAL_MAPENTRY.equals(hintValue)) {
102                 rootAction.processSuccessor(this);
103             } else {
104                 throw new DDTException("Unknown hint (" + hintValue
105                         + ")- stop processing.");
106             }
107         } else {
108             rootAction = this;
109         }
110         this.pop();
111         return this;
112     }
113 
114     public void processNoSuccessor() {
115         // process direct object call providing no parameters (empty tag)
116         IAction action = new AttributeListCreatorAction(
117                 new HashMap<String, String>());
118         action.inject();
119         action.setValue(new Vector());
120         this.insert(action);
121         action.process();
122     }
123 
124     /*
125      * (non-Javadoc)
126      * 
127      * @see junitx.ddtunit.parser.ActionBase#inject()
128      */
129     public IAction inject() {
130         String type = (String) this.attrMap.get(ParserConstants.XML_ATTR_TYPE);
131         String id = (String) this.attrMap.get(ParserConstants.XML_ATTR_ID);
132         this.injectedObject = new TypedObject(id, type);
133         return this;
134     }
135 
136     public void processSuccessor(IAction successor) {
137         log.debug("processSuccessor(" + successor + ") - START");
138         // create attribute list action and insert after rootAction
139         if (HintTypes.ATTRLIST.equals(successor.getHint())) {
140             String rootType = this.getType();
141             if (TypedObject.UNKNOWN_TYPE.equals(rootType)) {
142                 rootType = successor.getTypeFromRoot();
143             }
144             // do create object by calling the constructor
145             // extract Class array from signature list to select
146             // constructor
147             Class[] sigClasses = getClassesFrom((List) successor.getValue());
148             Object[] sigObjects = getObjectsFrom((List) successor.getValue());
149             String methodName = this.getAttribute("method");
150             Object obj = null;
151             if (methodName == null || "".equals(methodName)
152                     || "constructor".equals(methodName)) {
153                 Constructor constructor = (Constructor) ClassAnalyser
154                     .findMethodByParams(rootType,
155                         ClassAnalyser.CLASS_CONSTRUCTOR, sigClasses);
156                 checkForValidMethod(constructor, sigClasses, "constructor");
157                 try {
158                     obj = constructor.newInstance(sigObjects);
159                 } catch (Exception ex) {
160                     throw new DDTException(
161                             "Error on object creation by constructor", ex);
162                 }
163             } else {
164                 String callType = this.getAttribute("calltype");
165                 if (callType == null || "".equals(callType)) {
166                     callType = rootType;
167                 }
168                 Method method = (Method) ClassAnalyser.findMethodByParams(
169                     callType, methodName, sigClasses);
170                 checkForValidMethod(method, sigClasses, methodName);
171                 try {
172                     if (Modifier.isStatic(method.getModifiers())) {
173                         obj = method.invoke(null, sigObjects);
174                     } else {
175                         Class callClazz = Class.forName(callType);
176                         Object callObj = callClazz.newInstance();
177                         obj = method.invoke(callObj, sigObjects);
178                     }
179                 } catch (Exception ex) {
180                     throw new DDTException(
181                             "Error on object creation by method call", ex);
182                 }
183             }
184             this.setValue(obj);
185             this.successorProcessed = true;
186         } else if (HintTypes.INTERNAL_MAPENTRY.equals(this.getHint())) {
187             try {
188                 PrivilegedAccessor.setFieldValue(this.getValue(), successor
189                     .getId(), successor.getObject());
190             } catch (Exception ex) {
191                 throw new DDTTestDataException("Error filling map entry "
192                         + this.getId(), ex);
193             }
194         } else {
195             // ARRAY successor
196             Map attribMap = new HashMap();
197             IAction attribListAction = ActionFactory.getAction(
198                 ActionState.ATTRLIST_CREATION, attribMap);
199             this.insert(attribListAction);
200             try {
201                 // create container
202                 attribListAction.createObject();
203                 // initialize with first list element
204                 ((List<TypedObject>) attribListAction.getValue()).add(successor
205                     .getObject());
206             } catch (Exception ex) {
207                 throw new DDTException("Error on action processing", ex);
208             }
209         }
210     }
211 
212     /**
213      * @param sigClasses
214      * @param constructor
215      */
216     private void checkForValidMethod(Object caller, Class[] sigClasses,
217             String type) {
218         if (caller == null) {
219             StringBuffer sb = new StringBuffer("No method found! Expected ")
220                 .append(this.getType()).append(".").append(type).append("(");
221             for (int count = 0; count < sigClasses.length; count++) {
222                 sb.append(sigClasses[count].getName());
223                 if (count < sigClasses.length) {
224                     sb.append(", ");
225                 }
226             }
227             sb.append(")");
228             throw new DDTException(sb.toString());
229         }
230     }
231 
232     /**
233      * Process a list of RecordBase objects and return the array of Class
234      * elements of provided records
235      * 
236      * @param recordList to process
237      * @return array of element classes
238      */
239     private Class[] getClassesFrom(List recordList) {
240         int max = recordList.size();
241         Class[] sigClasses;
242         sigClasses = new Class[max];
243         for (int pos = 0; pos < max; pos++) {
244             TypedObject tObject = (TypedObject) recordList.get(pos);
245             String objectType = tObject.getType();
246             try {
247 
248                 sigClasses[pos] = Class.forName(objectType);
249             } catch (ClassNotFoundException ex) {
250                 throw new DDTException("Could not instanciate class for "
251                         + objectType, ex);
252             }
253         }
254         return sigClasses;
255     }
256 
257     /**
258      * Process a list of RecordBase objects and return the array of instanciated
259      * Objects of provided records
260      * 
261      * @param objectList to process
262      * @return array of element classes
263      */
264     private Object[] getObjectsFrom(List objectList) {
265         int max = objectList.size();
266         Object[] sigObjects;
267         sigObjects = new Object[max];
268         for (int pos = 0; pos < max; pos++) {
269             TypedObject tObject = (TypedObject) objectList.get(pos);
270             sigObjects[pos] = tObject.getValue();
271         }
272         return sigObjects;
273     }
274 
275 }