001: //$Id: CallCreatorAction.java 250 2006-08-25 21:30:26Z jg_hamburg $
002: /********************************************************************************
003: * DDTUnit, a Datadriven Approach to Unit- and Moduletesting
004: * Copyright (c) 2004, Joerg and Kai Gellien
005: * All rights reserved.
006: *
007: * The Software is provided under the terms of the Common Public License 1.0
008: * as provided with the distribution of DDTUnit in the file cpl-v10.html.
009: * Redistribution and use in source and binary forms, with or without
010: * modification, are permitted provided that the following conditions
011: * are met:
012: *
013: * + Redistributions of source code must retain the above copyright
014: * notice, this list of conditions and the following disclaimer.
015: *
016: * + Redistributions in binary form must reproduce the above
017: * copyright notice, this list of conditions and the following
018: * disclaimer in the documentation and/or other materials provided
019: * with the distribution.
020: *
021: * + Neither the id of the authors or DDTUnit, nor the
022: * names of its contributors may be used to endorse or promote
023: * products derived from this software without specific prior
024: * written permission.
025: *
026: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
027: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
028: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
029: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
030: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
031: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
032: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
033: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
034: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
035: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
036: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
037: ********************************************************************************/package junitx.ddtunit.data.processing;
038:
039: import java.lang.reflect.Constructor;
040: import java.lang.reflect.Method;
041: import java.lang.reflect.Modifier;
042: import java.util.HashMap;
043: import java.util.List;
044: import java.util.Map;
045: import java.util.Vector;
046:
047: import junitx.ddtunit.DDTException;
048: import junitx.ddtunit.data.DDTTestDataException;
049: import junitx.ddtunit.data.TypedObject;
050: import junitx.ddtunit.util.ClassAnalyser;
051: import junitx.ddtunit.util.PrivilegedAccessor;
052:
053: /**
054: * This class contains object state and other information to create object from
055: * SAX event stream.
056: *
057: * @author jg
058: */
059: public class CallCreatorAction extends ActionBase {
060: /**
061: *
062: * Constructor used as standard constructor to instanciate actions of this
063: * type
064: *
065: * @param attrMap
066: */
067: public CallCreatorAction(Map<String, String> attrMap) {
068: super (attrMap);
069: }
070:
071: /*
072: * (non-Javadoc)
073: *
074: * @see junitx.ddtunit.parser.ActionBase#process()
075: */
076: public IAction process() {
077: log.debug("process CallCreator - START");
078: if (!this .successorProcessed) {
079: processNoSuccessor();
080: }
081: IAction rootAction = this .getPrevious();
082: if (rootAction != null) {
083: String hintValue = rootAction.getHint();
084:
085: if (HintTypes.COLLECTION.equals(hintValue)) {
086: rootAction.processSuccessor(this );
087: } else if (HintTypes.MAP.equals(hintValue)) {
088: rootAction.processSuccessor(this );
089: } else if (HintTypes.ATTRLIST.equals(hintValue)) {
090: rootAction.processSuccessor(this );
091: } else if (HintTypes.FIELDS.equals(hintValue)) {
092: rootAction.processSuccessor(this );
093: } else if (HintTypes.CONSTRUCTOR.equals(hintValue)
094: || HintTypes.CALL.equals(hintValue)) {
095: rootAction.processSuccessor(this );
096: } else if (HintTypes.BEAN.equals(hintValue)) {
097: rootAction.processSuccessor(this );
098: } else if (HintTypes.ARRAY.equals(hintValue)) {
099: rootAction.processSuccessor(this );
100: } else if (HintTypes.INTERNAL_MAPENTRY.equals(hintValue)) {
101: rootAction.processSuccessor(this );
102: } else {
103: throw new DDTException("Unknown hint (" + hintValue
104: + ")- stop processing.");
105: }
106: } else {
107: rootAction = this ;
108: }
109: this .pop();
110: return this ;
111: }
112:
113: public void processNoSuccessor() {
114: // process direct object call providing no parameters (empty tag)
115: IAction action = new AttributeListCreatorAction(
116: new HashMap<String, String>());
117: action.inject();
118: action.setValue(new Vector());
119: this .insert(action);
120: action.process();
121: }
122:
123: /*
124: * (non-Javadoc)
125: *
126: * @see junitx.ddtunit.parser.ActionBase#inject()
127: */
128: public IAction inject() {
129: String type = (String) this .attrMap
130: .get(ParserConstants.XML_ATTR_TYPE);
131: String id = (String) this .attrMap
132: .get(ParserConstants.XML_ATTR_ID);
133: this .injectedObject = new TypedObject(id, type);
134: return this ;
135: }
136:
137: public void processSuccessor(IAction successor) {
138: log.debug("processSuccessor(" + successor + ") - START");
139: // create attribute list action and insert after rootAction
140: if (HintTypes.ATTRLIST.equals(successor.getHint())) {
141: String rootType = this .getType();
142: if (TypedObject.UNKNOWN_TYPE.equals(rootType)) {
143: rootType = successor.getTypeFromRoot();
144: }
145: // do create object by calling the constructor
146: // extract Class array from signature list to select
147: // constructor
148: Class[] sigClasses = getClassesFrom((List) successor
149: .getValue());
150: Object[] sigObjects = getObjectsFrom((List) successor
151: .getValue());
152: String methodName = this .getAttribute("method");
153: Object obj = null;
154: if (methodName == null || "".equals(methodName)
155: || "constructor".equals(methodName)) {
156: Constructor constructor = (Constructor) ClassAnalyser
157: .findMethodByParams(rootType,
158: ClassAnalyser.CLASS_CONSTRUCTOR,
159: sigClasses);
160: checkForValidMethod(constructor, sigClasses,
161: "constructor");
162: try {
163: obj = constructor.newInstance(sigObjects);
164: } catch (Exception ex) {
165: throw new DDTException(
166: "Error on object creation by constructor",
167: ex);
168: }
169: } else {
170: String callType = this .getAttribute("calltype");
171: if (callType == null || "".equals(callType)) {
172: callType = rootType;
173: }
174: Method method = (Method) ClassAnalyser
175: .findMethodByParams(callType, methodName,
176: sigClasses);
177: checkForValidMethod(method, sigClasses, methodName);
178: try {
179: if (Modifier.isStatic(method.getModifiers())) {
180: obj = method.invoke(null, sigObjects);
181: } else {
182: Class callClazz = Class.forName(callType);
183: Object callObj = callClazz.newInstance();
184: obj = method.invoke(callObj, sigObjects);
185: }
186: } catch (Exception ex) {
187: throw new DDTException(
188: "Error on object creation by method call",
189: ex);
190: }
191: }
192: this .setValue(obj);
193: this .successorProcessed = true;
194: } else if (HintTypes.INTERNAL_MAPENTRY.equals(this .getHint())) {
195: try {
196: PrivilegedAccessor.setFieldValue(this .getValue(),
197: successor.getId(), successor.getObject());
198: } catch (Exception ex) {
199: throw new DDTTestDataException(
200: "Error filling map entry " + this .getId(), ex);
201: }
202: } else {
203: // ARRAY successor
204: Map attribMap = new HashMap();
205: IAction attribListAction = ActionFactory.getAction(
206: ActionState.ATTRLIST_CREATION, attribMap);
207: this .insert(attribListAction);
208: try {
209: // create container
210: attribListAction.createObject();
211: // initialize with first list element
212: ((List<TypedObject>) attribListAction.getValue())
213: .add(successor.getObject());
214: } catch (Exception ex) {
215: throw new DDTException("Error on action processing", ex);
216: }
217: }
218: }
219:
220: /**
221: * @param sigClasses
222: * @param constructor
223: */
224: private void checkForValidMethod(Object caller, Class[] sigClasses,
225: String type) {
226: if (caller == null) {
227: StringBuffer sb = new StringBuffer(
228: "No method found! Expected ")
229: .append(this .getType()).append(".").append(type)
230: .append("(");
231: for (int count = 0; count < sigClasses.length; count++) {
232: sb.append(sigClasses[count].getName());
233: if (count < sigClasses.length) {
234: sb.append(", ");
235: }
236: }
237: sb.append(")");
238: throw new DDTException(sb.toString());
239: }
240: }
241:
242: /**
243: * Process a list of RecordBase objects and return the array of Class
244: * elements of provided records
245: *
246: * @param recordList to process
247: * @return array of element classes
248: */
249: private Class[] getClassesFrom(List recordList) {
250: int max = recordList.size();
251: Class[] sigClasses;
252: sigClasses = new Class[max];
253: for (int pos = 0; pos < max; pos++) {
254: TypedObject tObject = (TypedObject) recordList.get(pos);
255: String objectType = tObject.getType();
256: try {
257:
258: sigClasses[pos] = Class.forName(objectType);
259: } catch (ClassNotFoundException ex) {
260: throw new DDTException(
261: "Could not instanciate class for " + objectType,
262: ex);
263: }
264: }
265: return sigClasses;
266: }
267:
268: /**
269: * Process a list of RecordBase objects and return the array of instanciated
270: * Objects of provided records
271: *
272: * @param objectList to process
273: * @return array of element classes
274: */
275: private Object[] getObjectsFrom(List objectList) {
276: int max = objectList.size();
277: Object[] sigObjects;
278: sigObjects = new Object[max];
279: for (int pos = 0; pos < max; pos++) {
280: TypedObject tObject = (TypedObject) objectList.get(pos);
281: sigObjects[pos] = tObject.getValue();
282: }
283: return sigObjects;
284: }
285:
286: }
|