View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2008 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.impl.wsdl.teststeps;
14  
15  import java.beans.PropertyChangeEvent;
16  import java.beans.PropertyChangeListener;
17  import java.beans.PropertyChangeSupport;
18  import java.util.ArrayList;
19  import java.util.List;
20  
21  import org.apache.log4j.Logger;
22  import org.apache.xmlbeans.XmlBoolean;
23  import org.apache.xmlbeans.XmlObject;
24  
25  import com.eviware.soapui.config.GotoConditionConfig;
26  import com.eviware.soapui.config.GotoConditionTypeConfig;
27  import com.eviware.soapui.config.GotoStepConfig;
28  import com.eviware.soapui.config.TestStepConfig;
29  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase;
30  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
31  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
32  import com.eviware.soapui.model.support.XPathReference;
33  import com.eviware.soapui.model.support.XPathReferenceContainer;
34  import com.eviware.soapui.model.support.XPathReferenceImpl;
35  import com.eviware.soapui.model.testsuite.TestProperty;
36  import com.eviware.soapui.model.testsuite.TestRunContext;
37  import com.eviware.soapui.model.testsuite.TestRunner;
38  import com.eviware.soapui.model.testsuite.TestStep;
39  import com.eviware.soapui.model.testsuite.TestStepResult;
40  import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus;
41  import com.eviware.soapui.support.StringUtils;
42  import com.eviware.soapui.support.UISupport;
43  
44  /***
45   * TestStep that moves execution to another step based on the contents of a XML Property
46   * 
47   * @author ole.matzura
48   */
49  
50  public class WsdlGotoTestStep extends WsdlTestStepWithProperties implements XPathReferenceContainer
51  {
52  	private GotoStepConfig gotoStepConfig;
53  	private List<GotoCondition> conditions = new ArrayList<GotoCondition>();
54  	private boolean canceled;
55  	
56  	private final static Logger log = Logger.getLogger( WsdlGotoTestStep.class );
57  	
58  	public WsdlGotoTestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest)
59  	{
60  		super(testCase, config, true, forLoadTest);
61  		
62  		if( !forLoadTest )
63  		{
64  			setIcon( UISupport.createImageIcon("/goto.gif"));
65  		}
66  	}
67  	
68  	@Override
69  	public void afterLoad() 
70  	{
71  		TestStepConfig config = getConfig();
72  		
73  		if( config.getConfig() == null )
74  		{
75  			gotoStepConfig = (GotoStepConfig) config.addNewConfig().changeType( GotoStepConfig.type );
76  		}
77  		else
78  		{
79  			gotoStepConfig = (GotoStepConfig) config.getConfig().changeType(GotoStepConfig.type);
80  			for( int c = 0; c < gotoStepConfig.sizeOfConditionArray(); c++ )
81  			{
82  				conditions.add( new GotoCondition( gotoStepConfig.getConditionArray( c )));
83  			}	
84  		}
85  		
86  		super.afterLoad();
87  	}
88  
89  	public void resetConfigOnMove(TestStepConfig config)
90  	{
91  		super.resetConfigOnMove( config );
92  		
93  		gotoStepConfig = (GotoStepConfig) config.getConfig().changeType(GotoStepConfig.type);
94  		for( int c = 0; c < gotoStepConfig.sizeOfConditionArray(); c++ )
95  		{
96  			conditions.get( c ).setConfig( gotoStepConfig.getConditionArray( c ));
97  		}	
98  	}
99  
100 	public TestStepResult run(TestRunner runner, TestRunContext context)
101 	{
102 		WsdlTestStepResult result = new WsdlTestStepResult( this );
103 		canceled = false;
104 		
105 		result.startTimer();
106 		
107 		WsdlTestRequestStep previousStep = (WsdlTestRequestStep) getTestCase().findPreviousStepOfType( 
108 				this, WsdlTestRequestStep.class );
109 		
110 		if( previousStep == null )
111 		{
112 			result.stopTimer();
113 			result.addMessage( "Failed to find previous request step from [" + getName() + "]" );
114 			result.setStatus( TestStepStatus.FAILED );
115 			return result;
116 		}
117 		
118 		GotoCondition target = runConditions( previousStep, context );
119 		if( target == null )
120 		{
121 			result.addMessage( "Missing matching condition, moving on." );
122 		}
123 		else
124 		{
125 			String targetStepName = target.getTargetStep();
126 			result.addMessage( "Matched condition [" + targetStepName + "], transferring to [" + targetStepName + "]" );
127 			runner.gotoStep( runner.getTestCase().getTestStepIndexByName( targetStepName ) );
128 		}
129 		
130 		result.stopTimer();
131 		result.setStatus( TestStepStatus.OK );
132 		return result;
133 	}
134 
135 	public GotoCondition runConditions(WsdlTestRequestStep previousStep, TestRunContext context)
136 	{
137 		for( GotoCondition condition : conditions )
138 		{
139 			if( canceled )
140 				break;
141 			
142 			try
143 			{
144 				if( condition.evaluate( previousStep, context ))
145 				{
146 					return condition;
147 				}
148 			}
149 			catch (Exception e)
150 			{
151 				log.error( "Error making condition " + condition.getName() + "; " + e );
152 			}
153 		}
154 		
155 		return null;
156 	}
157 
158 	public boolean cancel()
159 	{
160 		canceled = true;
161 		return canceled;
162 	}
163 	
164 	public int getConditionCount()
165 	{
166 		return conditions.size();
167 	}
168 	
169 	public GotoCondition getConditionAt( int index )
170 	{
171 		return conditions.get( index );
172 	}
173 	
174 	public GotoCondition addCondition( String name )
175 	{
176 		GotoCondition condition = new GotoCondition( gotoStepConfig.addNewCondition());
177 		condition.setName( name );
178 		condition.setType( GotoConditionTypeConfig.XPATH.toString() );
179 		conditions.add( condition );
180 		return condition;
181 	}
182 	
183 	public void removeConditionAt( int index )
184 	{
185 		conditions.remove( index );
186 		gotoStepConfig.removeCondition( index );
187 	}
188 	
189 	public void release()
190 	{
191 		super.release(); 
192 		
193 		for( GotoCondition condition : conditions )
194 		{
195 			condition.release();
196 		}
197 	}
198 
199 	public class GotoCondition implements PropertyChangeListener
200 	{
201 		public final static String TARGET_STEP_PROPERTY = "target_step";
202 		
203 		private GotoConditionConfig conditionConfig;
204 		private TestStep currentStep;
205 		private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this );
206 
207 		public GotoCondition(GotoConditionConfig conditionConfig)
208 		{
209 			this.conditionConfig = conditionConfig;
210 			initListeners();
211 		}
212 		
213 		public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener )
214 		{
215 			propertyChangeSupport.addPropertyChangeListener( propertyName, listener );
216 		}
217 
218 		public void addPropertyChangeListener( PropertyChangeListener listener )
219 		{
220 			propertyChangeSupport.addPropertyChangeListener( listener );
221 		}
222 		
223 		public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener )
224 		{
225 			propertyChangeSupport.removePropertyChangeListener( propertyName, listener );
226 		}
227 
228 		public void removePropertyChangeListener( PropertyChangeListener listener )
229 		{
230 			propertyChangeSupport.removePropertyChangeListener( listener );
231 		}
232 		
233 		private void initListeners()
234 		{
235 			release();
236 			
237 			if( getTargetStep() != null )
238 			{
239 				int index = getTestCase().getTestStepIndexByName( getTargetStep() );
240 				if( index != -1 )
241 				{
242 					currentStep = getTestCase().getTestStepAt( index );
243 					currentStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, this );
244 				}
245 			}
246 		}
247 		
248 		public void release()
249 		{
250 			if( currentStep != null )
251 				currentStep.removePropertyChangeListener( this );
252 		}
253 	
254 		public boolean evaluate(WsdlTestRequestStep previousStep, TestRunContext context) throws Exception
255 		{
256 			if( getExpression() == null || getExpression().trim().length() == 0 )
257 				throw new Exception( "Missing expression in condition [" + getName() + "]" );
258 			
259 			if( getTargetStep() == null || getTargetStep().trim().length() == 0 )
260 				throw new Exception( "Missing target step in condition [" + getName() + "]" );
261 			
262 			if( getType().equals( GotoConditionTypeConfig.XPATH.toString() ))
263 			{
264 				XmlObject xmlObject = XmlObject.Factory.parse( previousStep.getTestRequest().getResponse().getContentAsString());
265 				
266 				String expression = PropertyExpansionUtils.expandProperties( context, getExpression() );
267 				XmlObject[] selectPath = xmlObject.selectPath( expression );
268 				if( selectPath.length == 1 && selectPath[0] instanceof XmlBoolean )
269 				{
270 					if( ((XmlBoolean)selectPath[0]).getBooleanValue() )
271 					{
272 						return true;
273 					}
274 				}
275 			}
276 			else
277 			{
278 				log.error( "Unkown condition type: " + getType() );
279 			}
280 			
281 			return false;
282 		}
283 
284 		protected void setConfig(GotoConditionConfig conditionConfig)
285 		{
286 			this.conditionConfig = conditionConfig;
287 		}
288 
289 		public String getType()
290 		{
291 			return conditionConfig.getType();
292 		}
293 		
294 		public String getName()
295 		{
296 			return conditionConfig.getName();
297 		}
298 
299 		public String getExpression()
300 		{
301 			return conditionConfig.getExpression();
302 		}
303 		
304 		public String getTargetStep()
305 		{
306 			return conditionConfig.getTargetStep();
307 		}
308 		
309 		public void setType( String type )
310 		{
311 			conditionConfig.setType( type );
312 		}
313 
314 		public void setName( String name )
315 		{
316 			conditionConfig.setName( name );
317 		}
318 		
319 		public void setExpression( String expression )
320 		{
321 			conditionConfig.setExpression( expression );
322 		}
323 		
324 		public void setTargetStep( String targetStep )
325 		{
326 			String oldStep = getTargetStep();
327 			conditionConfig.setTargetStep( targetStep );
328 			initListeners();
329 			propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, oldStep, targetStep );
330 		}
331 
332 		public void propertyChange(PropertyChangeEvent evt)
333 		{
334 			conditionConfig.setTargetStep( evt.getNewValue().toString() );
335 			propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, evt.getOldValue(), evt.getNewValue() );
336 		}
337 
338 		public TestProperty getSourceProperty()
339 		{
340 			WsdlTestRequestStep previousStep = (WsdlTestRequestStep) getTestCase().findPreviousStepOfType( 
341 						WsdlGotoTestStep.this, WsdlTestRequestStep.class );
342 			return previousStep == null ? null : previousStep.getProperty( "Response" );
343 		}
344 	}
345 	
346 	public boolean hasProperties()
347 	{
348 		return false;
349 	}
350 	
351 	public PropertyExpansion[] getPropertyExpansions()
352 	{
353 		List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
354 		
355 		for( GotoCondition condition : conditions )
356 		{
357 			result.addAll( PropertyExpansionUtils.extractPropertyExpansions( this, condition, "expression") );
358 		}
359 		
360 		return result.toArray( new PropertyExpansion[result.size()] );
361 	}
362 	
363 	public XPathReference[] getXPathReferences()
364 	{
365 		List<XPathReference> result = new ArrayList<XPathReference>();
366 		
367 		for( GotoCondition condition : conditions )
368 		{
369 			if( StringUtils.hasContent( condition.getExpression() ))
370 				result.add( new XPathReferenceImpl( "Condition for " + condition.getName() + " GotoCondition in " + getName(), 
371 							condition.getSourceProperty(), condition, "expression" ));
372 		}
373 		
374 		return result.toArray( new XPathReference[result.size()] );
375 	}
376 }