001: //$Id: CollectionCreatorAction.java 342 2008-02-20 22:38:16Z 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.util.Collection;
040: import java.util.List;
041: import java.util.Map;
042:
043: import junitx.ddtunit.DDTException;
044: import junitx.ddtunit.data.DDTTestDataException;
045: import junitx.ddtunit.data.IDataSet;
046: import junitx.ddtunit.data.TestDataSet;
047: import junitx.ddtunit.data.TypedObject;
048:
049: import org.apache.log4j.Logger;
050:
051: /**
052: * This class contains object state and other information to create object from
053: * SAX event stream.
054: *
055: * @author jg
056: */
057: public class CollectionCreatorAction extends ActionBase {
058: protected Logger log = Logger
059: .getLogger(CollectionCreatorAction.class);
060: protected int elementCount;
061:
062: /**
063: *
064: * Constructor used as standard constructor to instanciate actions of this
065: * type
066: *
067: * @param attrMap
068: */
069: public CollectionCreatorAction(Map<String, String> attrMap) {
070: super (attrMap);
071: this .elementCount = 0;
072: }
073:
074: /*
075: * (non-Javadoc)
076: *
077: * @see junitx.ddtunit.parser.ActionBase#process()
078: */
079: public IAction process() {
080: log.debug("process CollectionCreator - START");
081: IAction rootAction = getPrevious();
082: if (!this .successorProcessed) {
083: processNoSuccessor();
084: }
085: if (rootAction != null) {
086: String hintValue = rootAction.getHint();
087:
088: if (HintTypes.COLLECTION.equals(hintValue)) {
089: rootAction.processSuccessor(this );
090: } else if (HintTypes.ARRAY.equals(hintValue)) {
091: rootAction.processSuccessor(this );
092: } else if (HintTypes.ATTRLIST.equals(hintValue)) {
093: rootAction.processSuccessor(this );
094: } else if (HintTypes.BEAN.equals(hintValue)) {
095: rootAction.processSuccessor(this );
096: } else if (HintTypes.FIELDS.equals(hintValue)) {
097: rootAction.processSuccessor(this );
098: } else {
099: throw new UnsupportedOperationException(
100: "CollectionCreatorAction does not support hint '"
101: + hintValue + "'");
102: }
103: } else {
104: rootAction = this ;
105: }
106: // if rootAction is null simply return action -> base object is a
107: // collection
108: pop();
109: // do not forget to process the actual root element
110: IAction previousRootAction = rootAction.getPrevious();
111: if (previousRootAction != null) {
112: if (!((previousRootAction instanceof CollectionCreatorAction) || (previousRootAction instanceof SubelementCreatorAction))) {
113: rootAction = rootAction.process();
114: }
115: }
116: return rootAction;
117: }
118:
119: public void processNoSuccessor() {
120: this .createObject();
121: }
122:
123: public void processSuccessor(IAction successor) {
124: log.debug("processSuccessor(" + successor + ") - START");
125: if (HintTypes.CONTENT.equals(successor.getHint())) {
126: String content = successor.getValue().toString();
127: if (!ContentCreatorAction.CONTENT_NULL.equals(content)) {
128: throw new DDTException(
129: "Only \"!NULL!\" supported in Collection type");
130: }
131: } else {
132: try {
133: this .createObject();
134: this .elementCount += 1;
135: // if no reference is set or if collection is sorted simply add
136: // object (maybe an empty one)
137:
138: // check if successor contains referenceInfo
139: if (HintTypes.ATTRLIST.equals(successor.getHint())
140: && ((SubelementCreatorAction) successor)
141: .hasReferenceInfo()) {
142: TypedObject destObject;
143: String linkType = successor.getType();
144: if (linkType == null) {
145: destObject = new TypedObject(successor
146: .getAttribute("refid"));
147: } else {
148: destObject = new TypedObject(successor
149: .getAttribute("refid"), linkType);
150: }
151: IReferenceInfo refInfo;
152: if (isSorted()) {
153: refInfo = new CollectionReferenceInfo(this
154: .getObject(), destObject,
155: this .elementCount);
156: // reserve position for referenced object
157: ((List) this .getValue()).add(null);
158: } else {
159: refInfo = new CollectionReferenceInfo(this
160: .getObject(), destObject,
161: CollectionReferenceInfo.noPosition);
162: }
163: add(refInfo);
164: } else {
165: ((Collection) this .getValue()).add(successor
166: .getValue());
167: }
168: } catch (Exception ex) {
169: throw new DDTException(
170: "Error on Collection element processing", ex);
171: }
172: }
173: this .successorProcessed = true;
174: }
175:
176: private boolean isSorted() {
177: boolean found = verifyInterface(this .getType(), List.class);
178: return found;
179: }
180:
181: /*
182: * (non-Javadoc)
183: *
184: * @see junitx.ddtunit.parser.ActionBase#inject()
185: */
186: public IAction inject() {
187: String type = (String) this .attrMap
188: .get(ParserConstants.XML_ATTR_TYPE);
189: String id = (String) this .attrMap
190: .get(ParserConstants.XML_ATTR_ID);
191: // check if type is based on java.util.Collection
192: try {
193: if (type == null
194: && ParserConstants.XML_ELEM_ITEM.equals(id)) {
195: type = TypedObject.UNKNOWN_TYPE;
196: } else if (HintTypes.ARRAY.equals(this .getHint())) {
197: // do nothing
198: } else {
199: boolean found = verifyInterface(type, Collection.class);
200: if (!found) {
201: throw new DDTException(
202: "Container class '"
203: + type
204: + "' does not implement java.util.Collection.");
205: }
206: }
207: } catch (Exception ex) {
208: throw new DDTException("Container class '" + type
209: + "' does not implement java.util.Collection.", ex);
210: }
211: this .injectedObject = new TypedObject(id, type);
212: return this ;
213: }
214:
215: private boolean verifyInterface(String clazzType, Class interFace) {
216: Class clazz;
217: try {
218: clazz = Class.forName(clazzType);
219: } catch (ClassNotFoundException ex) {
220: throw new DDTTestDataException("Wrong data type "
221: + clazzType, ex);
222: }
223: Class super clazz = clazz;
224: Class[] interfaces = null;
225: boolean found = false;
226: while (!found && super clazz != null) {
227: found = isImplementing(super clazz, interFace);
228: if (!found) {
229: super clazz = super clazz.getSuperclass();
230: }
231: }
232: return found;
233: }
234:
235: private boolean isImplementing(Class clazz, Class interFace) {
236: boolean found = false;
237: Class[] interfaces = clazz.getInterfaces();
238: for (Class inter : interfaces) {
239: if (interFace.equals(inter)) {
240: found = true;
241: break;
242: } else {
243: found = isImplementing(inter, interFace);
244: }
245: }
246: return found;
247: }
248:
249: static class CollectionReferenceInfo extends ReferenceInfoBase {
250: protected int position;
251: static int noPosition = -1;
252:
253: public CollectionReferenceInfo(TypedObject source,
254: TypedObject destination, int position) {
255: super (source, destination);
256: this .position = position;
257: }
258:
259: public void raiseRankOf(IReferenceInfo info) {
260: if (this .getDestId().equals(info.getSourceId())
261: && (this .getDestType().equals(info.getSourceType()) || TypedObject.UNKNOWN_TYPE
262: .equals(info.getDestType()))) {
263: if (this .getRank() >= info.getRank()) {
264: info.setRank(this .getRank() + 1);
265: }
266: }
267: }
268:
269: public void resolve(IDataSet dataSet, String groupId,
270: String testId) {
271: if (ParserConstants.UNKNOWN.equals(groupId)
272: && ParserConstants.UNKNOWN.equals(testId)) {
273: doResolution(dataSet);
274: } else if (!ParserConstants.UNKNOWN.equals(testId)) {
275: IDataSet groupSet = dataSet.get(groupId);
276: IDataSet testDataSet = null;
277: if (groupSet != null) {
278: testDataSet = groupSet.get(testId);
279: }
280: doResolution(testDataSet);
281: } else {
282: throw new DDTTestDataException(
283: "Do not process group data without testId");
284: }
285: }
286:
287: /**
288: * @param dataSet
289: * to resolve reference to
290: */
291: private void doResolution(IDataSet dataSet) {
292: TypedObject dest = dataSet.findObject(this .getDestId(),
293: this .getDestType());
294: TypedObject source = dataSet.getObject(this .getSourceId(),
295: this .getSourceType());
296: if (source == null && dataSet instanceof TestDataSet) {
297: source = ((TestDataSet) dataSet).getAssert(this
298: .getSourceId(), this .getSourceType());
299: }
300: if (dest != null && source != null) {
301: // if unsorted collection then just add to end
302: if (this .position == this .noPosition) {
303: ((Collection) source.getValue()).add(dest
304: .getValue());
305: } else {
306: ((List) source.getValue()).set(this .position - 1,
307: dest.getValue());
308: }
309: } else {
310: throw new DDTTestDataException(
311: "Error on processing references on testdata.");
312: }
313: }
314:
315: }
316: }
|