View Javadoc

1   //$Id: BeanCreatorAction.java 358 2009-08-05 13:58:44Z 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.Method;
41  import java.util.Collection;
42  import java.util.HashMap;
43  import java.util.List;
44  import java.util.Map;
45  import java.util.Vector;
46  
47  import junitx.ddtunit.DDTException;
48  import junitx.ddtunit.data.DDTTestDataException;
49  import junitx.ddtunit.data.TypedObject;
50  import junitx.ddtunit.util.ClassAnalyser;
51  
52  /**
53   * This class contains object state and other information to create object from
54   * SAX event stream.
55   * 
56   * @author jg
57   */
58  public class BeanCreatorAction extends ActionBase {
59  	/**
60  	 * 
61  	 * Constructor used as standard constructor to instanciate actions of this
62  	 * type
63  	 * 
64  	 * @param attrMap
65  	 */
66  	public BeanCreatorAction(Map attrMap) {
67  		super(attrMap);
68  	}
69  
70  	/*
71  	 * (non-Javadoc)
72  	 * 
73  	 * @see junitx.ddtunit.parser.ActionBase#process()
74  	 */
75  	public IAction process() {
76  		log.debug("process BeanCreator - START");
77  		IAction rootAction = this.getPrevious();
78  		if (!this.successorProcessed) {
79  			processNoSuccessor();
80  		}
81  		if (rootAction != null) {
82  			String hintValue = rootAction.getHint();
83  
84  			if (HintTypes.COLLECTION.equals(hintValue)) {
85  				rootAction.processSuccessor(this);
86  			} else if (HintTypes.MAP.equals(hintValue)) {
87  				rootAction.processSuccessor(this);
88  			} else if (HintTypes.ATTRLIST.equals(hintValue)) {
89  				rootAction.processSuccessor(this);
90  			} else if (HintTypes.FIELDS.equals(hintValue)) {
91  				rootAction.processSuccessor(this);
92  			} else if (HintTypes.CONSTRUCTOR.equals(hintValue)
93  					|| HintTypes.CALL.equals(hintValue)) {
94  				rootAction.processSuccessor(this);
95  			} else if (HintTypes.BEAN.equals(hintValue)) {
96  				rootAction.processSuccessor(this);
97  			} else if (HintTypes.ARRAY.equals(hintValue)) {
98  				rootAction.processSuccessor(this);
99  			} else if (HintTypes.INTERNAL_MAPENTRY.equals(hintValue)) {
100 				rootAction.processSuccessor(this);
101 			} else {
102 				throw new DDTException("Unknown hint (" + hintValue
103 						+ ")- stop processing.");
104 			}
105 		}
106 		this.pop();
107 		return this;
108 	}
109 
110 	/**
111 	 * If no content on tag is provided just instanciate object by default
112 	 * constructor.
113 	 */
114 	public void processNoSuccessor() {
115 		// process direct object call providing no parameters (empty tag)
116 		IAction action = new AttributeListCreatorAction(new HashMap());
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.get(ParserConstants.XML_ATTR_TYPE);
130 		String id = (String) this.attrMap.get(ParserConstants.XML_ATTR_ID);
131 		this.injectedObject = new TypedObject(id, type);
132 		return this;
133 	}
134 
135 	public void processSuccessor(IAction successor) {
136 		log.debug("processSuccessor(" + successor + ") - START");
137 		// create attribute list action and insert after rootAction
138 		if (HintTypes.ATTRLIST.equals(successor.getHint())) {
139 			List fields = (List) successor.getObject().getValue();
140 			TypedObject field = null;
141 			StringBuffer setter = new StringBuffer();
142 			try {
143 				// returned type is never used but method may specify this type
144 				// internally in injected object
145 				this.getType();
146 				if (this.getValue() == null) {
147 					this.createObject();
148 				}
149 				for (int count = 0; count < fields.size(); count++) {
150 					field = (TypedObject) fields.get(count);
151 					// check for existing setter
152 					setter.replace(0, setter.length(), "set");
153 					setter.append(field.getId().substring(0, 1).toUpperCase())
154 							.append(field.getId().substring(1));
155 					Class fieldClazz = null;
156 					if (field.getValue() != null) {
157 						fieldClazz = field.getValue().getClass();
158 						Class[] args = new Class[1];
159 						args[0] = fieldClazz;
160 						Method setMethod = (Method) ClassAnalyser
161 								.findMethodByParams(this.getType(), setter
162 										.toString(), args);
163 						setMethod.setAccessible(true);
164 						Object[] objs = new Object[1];
165 						objs[0] = field.getValue();
166 						setMethod.invoke(this.getValue(), objs);
167 					}
168 				}
169 			} catch (Exception ex) {
170 				StringBuffer sb = new StringBuffer("Error executing setter ")
171 						.append(this.getType())
172 						.append(".")
173 						.append(setter)
174 						.append("(...). ")
175 						.append(
176 								"Check if hint and setter are correct (Do not provide set-prefix!).");
177 				throw new DDTException(sb.toString(), ex);
178 			}
179 		} else if (HintTypes.COLLECTION.equals(successor.getHint())) {
180 			// provide a Collection as setter argument
181 			Collection param = (Collection) successor.getObject().getValue();
182 			TypedObject field = successor.getObject();
183 			StringBuffer setter = new StringBuffer();
184 			try {
185 				// returned type is never used but method may specify this type
186 				// internally in injected object
187 				this.getType();
188 				if (this.getValue() == null) {
189 					this.createObject();
190 				}
191 				// check for existing setter
192 				setter.replace(0, setter.length(), "set");
193 				setter.append(field.getId().substring(0, 1).toUpperCase())
194 						.append(field.getId().substring(1));
195 				Class fieldClazz = field.getValue().getClass();
196 				Class[] args = new Class[1];
197 				args[0] = fieldClazz;
198 				Method setMethod = (Method) ClassAnalyser.findMethodByParams(
199 						this.getType(), setter.toString(), args);
200 				setMethod.setAccessible(true);
201 				Object[] objs = new Object[1];
202 				objs[0] = field.getValue();
203 				setMethod.invoke(this.getValue(), objs);
204 			} catch (Exception ex) {
205 				StringBuffer sb = new StringBuffer("Error executing setter ")
206 						.append(this.getType())
207 						.append(".")
208 						.append(setter)
209 						.append("(...). ")
210 						.append(
211 								"Check if hint and setter are correct (Do not provide set-prefix!).");
212 				throw new DDTException(sb.toString(), ex);
213 			}
214 		} else if (HintTypes.CONTENT.equals(successor.getHint())) {
215 			if (!ContentCreatorAction.CONTENT_NULL.equals(successor.getValue()
216 					.toString())) {
217 				throw new DDTTestDataException(
218 						"Unsupported content for BeanCreator:"
219 								+ successor.getValue().toString());
220 			}
221 		} else {
222 			// ARRAY successor
223 			Map attribMap = new HashMap();
224 			IAction attribListAction = ActionFactory.getAction(
225 					ActionState.ATTRLIST_CREATION, attribMap);
226 			this.insert(attribListAction);
227 			try {
228 				// create container
229 				attribListAction.createObject();
230 				// initialize with first list element
231 				((List) attribListAction.getValue()).add(successor.getObject());
232 			} catch (Exception ex) {
233 				throw new DDTException("Error on action processing", ex);
234 			}
235 		}
236 		this.successorProcessed = true;
237 	}
238 
239 }