View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 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.XmlCursor;
23  import org.apache.xmlbeans.XmlException;
24  import org.apache.xmlbeans.XmlObject;
25  import org.apache.xmlbeans.XmlOptions;
26  import org.w3c.dom.DocumentFragment;
27  import org.w3c.dom.Element;
28  import org.w3c.dom.Node;
29  
30  import com.eviware.soapui.config.ValueTransferConfig;
31  import com.eviware.soapui.impl.wsdl.submit.filters.PropertyExpansionRequestFilter;
32  import com.eviware.soapui.model.iface.SubmitContext;
33  import com.eviware.soapui.model.support.TestSuiteListenerAdapter;
34  import com.eviware.soapui.model.testsuite.TestCase;
35  import com.eviware.soapui.model.testsuite.TestStep;
36  import com.eviware.soapui.model.testsuite.TestStepProperty;
37  import com.eviware.soapui.support.PropertyChangeNotifier;
38  import com.eviware.soapui.support.xml.XmlUtils;
39  
40  /***
41   * Class for transferring a property value between 2 test steps. This class is relatively complex due
42   * to backwards compatibility issues and to gracefull handling of references test steps and properties.
43   * 
44   * @author Ole.Matzura
45   */
46  
47  public class PropertyTransfer implements PropertyChangeNotifier
48  {
49  	private final static Logger log = Logger.getLogger( PropertyTransfer.class );
50  	
51  	public final static String SOURCE_PATH_PROPERTY = PropertyTransfer.class.getName() + "@sourcePath";
52  	public final static String SOURCE_TYPE_PROPERTY = PropertyTransfer.class.getName() + "@sourceProperty";
53  	public final static String SOURCE_STEP_PROPERTY = PropertyTransfer.class.getName() + "@sourceStep";
54  	public final static String TARGET_PATH_PROPERTY = PropertyTransfer.class.getName() + "@targetPath";
55  	public final static String TARGET_TYPE_PROPERTY = PropertyTransfer.class.getName() + "@targetProperty";
56  	public final static String TARGET_STEP_PROPERTY = PropertyTransfer.class.getName() + "@targetStep";
57  	public final static String NAME_PROPERTY = PropertyTransfer.class.getName() + "@name";
58  	public final static String CONFIG_PROPERTY = PropertyTransfer.class.getName() + "@config";
59  	
60  	private TestStep testStep;
61  	
62  	// create local copies since a deleted/changed valuetransfer can be referred to from a result 
63  	private ValueTransferConfig config;
64  	private String sourcePath;
65  	private String sourceType;
66  	private String targetPath;
67  	private String name;
68  	private String targetType;
69  	private String sourceStep;
70  	private String targetStep;
71  	
72  	private TestStep currentTargetStep;
73  	private TestStep currentSourceStep;
74  	private TestStepProperty currentTargetProperty;
75  	private TestStepProperty currentSourceProperty;
76  	
77  	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport( this );
78  	private StepNameChangeListener stepNameChangeListener = new StepNameChangeListener();
79  	private PropertyNameChangeListener propertyNameChangeListener = new PropertyNameChangeListener();
80  	private TestCase testCase;
81  
82  	private InternalTestSuiteListener testSuiteListener = new InternalTestSuiteListener();
83  
84  	public PropertyTransfer( TestStep testStep )
85  	{
86  		this( testStep, ValueTransferConfig.Factory.newInstance() );
87  	}
88  	
89  	public PropertyTransfer( TestStep testStep, ValueTransferConfig config )
90  	{
91  		this.testStep = testStep;
92  		
93  		if( testStep != null )
94  		{
95  			this.testCase = testStep.getTestCase();
96  			testCase.getTestSuite().addTestSuiteListener( testSuiteListener );
97  		}
98  		
99  		setConfig( config );
100 	}
101 	
102 	void setConfigOnMove( ValueTransferConfig config )
103 	{
104 		this.config = config;
105 	}
106 	
107 	void setConfig(ValueTransferConfig config)
108 	{
109 		releaseListeners();
110 		
111 		this.config = config;
112 		
113 		if( !config.isSetSetNullOnMissingSource() )
114 		{
115 			config.setSetNullOnMissingSource( true );
116 		}
117 		
118 		if( !config.isSetTransferTextContent() )
119 		{
120 			config.setTransferTextContent( true );
121 		}
122 		
123 		sourceStep = config.getSourceStep();
124 		if( sourceStep == null )
125 		{
126 			sourceStep = getSourceStepName();
127 			if( sourceStep != null )
128 				config.setSourceStep( sourceStep );
129 		}
130 		
131 		currentSourceStep = (sourceStep == null || testCase == null ) ? null : testCase.getTestStepByName( sourceStep );
132 
133 		sourceType = config.getSourceType();
134 		currentSourceProperty = currentSourceStep == null || sourceType == null ? null : currentSourceStep.getProperty( sourceType );
135 		
136 		sourcePath = config.getSourcePath();
137 
138 		targetStep = config.getTargetStep();
139 		if( targetStep == null )
140 		{
141 			targetStep = getTargetStepName();
142 			if( targetStep != null )
143 				config.setTargetStep( targetStep );
144 		}
145 		
146 		currentTargetStep = (targetStep == null || testCase == null ) ? null : testCase.getTestStepByName( targetStep );
147 
148 		targetType = config.getTargetType();
149 		currentTargetProperty = currentTargetStep == null || targetType == null ? null : currentTargetStep.getProperty( targetType );
150 		
151 		targetPath = config.getTargetPath();
152 		
153 		name = config.getName();
154 		initListeners();
155 		
156 		propertyChangeSupport.firePropertyChange( CONFIG_PROPERTY, null, null );
157 	}
158 	
159 	private void initListeners()
160 	{
161 		if( currentSourceStep != null )
162 		{
163 			currentSourceStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
164 			((WsdlTestStep)currentSourceStep).addTestStepListener( propertyNameChangeListener );
165 		}
166 
167 		if( currentTargetStep != null )
168 		{
169 			currentTargetStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
170 			((WsdlTestStep)currentTargetStep).addTestStepListener( propertyNameChangeListener );
171 		}
172 	}
173 	
174 	public void releaseListeners()
175 	{
176 		if( currentSourceStep != null )
177 		{
178 			currentSourceStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
179 			((WsdlTestStep)currentSourceStep).removeTestStepListener( propertyNameChangeListener );
180 		}
181 
182 		if( currentTargetStep != null )
183 		{
184 			currentTargetStep.removePropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
185 			((WsdlTestStep)currentTargetStep).removeTestStepListener( propertyNameChangeListener );
186 		}
187 		
188 		PropertyChangeListener[] listeners = propertyChangeSupport.getPropertyChangeListeners();
189 		for( PropertyChangeListener listener : listeners )
190 			propertyChangeSupport.removePropertyChangeListener( listener );
191 	}
192 	
193 	public void release()
194 	{
195 		releaseListeners();
196 		testCase.getTestSuite().removeTestSuiteListener( testSuiteListener );
197 	}
198 	
199 	public ValueTransferConfig getConfig()
200 	{
201 		return config;
202 	}
203 
204 	public String getSourcePath()
205 	{
206 		return sourcePath;
207 	}
208 	
209 	public String getTargetPath()
210 	{
211 		return targetPath;
212 	}
213 	
214 	public TestStepProperty getSourceProperty()
215 	{
216 		if( sourceType == null )
217 			return null;
218 		
219 		if( currentSourceProperty != null )
220 			return currentSourceProperty;
221 		
222 		TestStep actualSourceStep = getSourceStep();
223 		return actualSourceStep == null ? null : actualSourceStep.getProperty( sourceType );
224 	}
225 	
226 	public String [] transferProperties(SubmitContext context) throws PropertyTransferException
227 	{
228 		TestStepProperty sourceProperty = getSourceProperty();
229 		TestStepProperty targetProperty = getTargetProperty();
230 		
231 		try
232 		{
233 			if (sourceProperty == null)
234 				throw new Exception("Missing source property");
235 			if (targetProperty == null)
236 				throw new Exception("Missing target property");
237 			if (sourceProperty.getValue() == null && !getSetNullOnMissingSource() && !getIgnoreEmpty() )
238 				throw new Exception("Source property is null");
239 			
240 			if (!hasSourcePath() && !hasTargetPath())
241 			{
242 				if( !getIgnoreEmpty() || (sourceProperty.getValue() != null && sourceProperty.getValue().length() > 0))
243 					return transferStringToString(sourceProperty, targetProperty);
244 			}
245 			else if (hasSourcePath() && hasTargetPath())
246 			{
247 					return transferXmlToXml(sourceProperty, targetProperty, context);
248 			}
249 			else if (hasSourcePath() && !hasTargetPath())
250 			{
251 				return new String[] { transferXmlToString(sourceProperty, targetProperty, context) };
252 			}
253 			else if (!hasSourcePath() && hasTargetPath())
254 			{
255 				if( !getIgnoreEmpty() || (sourceProperty.getValue() != null && sourceProperty.getValue().length() > 0))
256 					return transferStringToXml(sourceProperty, targetProperty, context);
257 			}
258 		}
259 		catch (Exception e)
260 		{
261 			throw new PropertyTransferException( e.toString(), getSourceStepName(), sourceProperty, 
262 					getTargetStepName(), targetProperty );
263 		}		
264 		
265 		return new String[0];
266 	}
267 
268 	private boolean hasTargetPath()
269 	{
270 		String path = getTargetPath();
271 		return path != null && path.trim().length() > 0 ;
272 	}
273 
274 	private boolean hasSourcePath()
275 	{
276 		String path = getSourcePath();
277 		return path != null && path.trim().length() > 0 ;
278 	}
279 
280 	protected String[] transferStringToString(TestStepProperty sourceProperty, TestStepProperty targetProperty)
281 	{
282 		String value = sourceProperty.getValue();
283 		targetProperty.setValue( value );
284 		return new String[]{ value};
285 	}
286 
287 	protected String[] transferXmlToXml( TestStepProperty sourceProperty, TestStepProperty targetProperty, SubmitContext context) throws XmlException, Exception
288 	{
289 		String sourcePropertyValue = sourceProperty.getValue();
290 		XmlObject sourceXmlObject = XmlObject.Factory.parse( sourcePropertyValue );
291 		XmlCursor sourceXml = sourceXmlObject.newCursor();
292 		
293 		String targetPropertyValue = targetProperty.getValue();
294 		XmlObject targetXmlObject = XmlObject.Factory.parse( targetPropertyValue );
295 		XmlCursor targetXml = targetXmlObject.newCursor();
296 
297 		XmlCursor lastSource = null;
298 		
299 		try
300 		{		
301 			List<String> result = new ArrayList<String>();
302 
303 			targetXml.selectPath( PropertyExpansionRequestFilter.expandProperties( context, getTargetPath()) );
304 			
305 			if( !targetXml.hasNextSelection() )
306 				throw new Exception( "Missing match for Target path [" + getTargetPath() + "]" );
307 			
308 			sourceXml.selectPath( PropertyExpansionRequestFilter.expandProperties( context, getSourcePath()) );
309 			
310 			if( !sourceXml.hasNextSelection() )
311 			{
312 				if( getSetNullOnMissingSource() )
313 				{
314 					while( targetXml.toNextSelection() )
315 					{
316 						result.add( setNodeValue( null, targetXml.getDomNode() ));
317 						if( !getTransferToAll())
318 							break;
319 					}
320 				}
321 				else if( !getIgnoreEmpty() )
322 					throw new Exception( "Missing match for Source path [" + getSourcePath() + "]" );
323 			}
324 			else
325 			{
326 				boolean hasSource = sourceXml.toNextSelection();
327 				boolean hasTarget = targetXml.toNextSelection();
328 				
329 				while( hasSource && hasTarget )
330 				{
331 					if( lastSource != null )
332 						lastSource.dispose();
333 					
334 					lastSource = sourceXml.newCursor();
335 					result.add( transferXmlValue( sourceXml, targetXml ));
336 					
337 					hasSource = sourceXml.toNextSelection();
338 					hasTarget = targetXml.toNextSelection();
339 				}
340 			
341 				if( getTransferToAll() && !hasSource && hasTarget && lastSource != null )
342 				{
343 					while( hasTarget )
344 					{
345 						result.add( transferXmlValue( lastSource, targetXml ));
346 						hasTarget = targetXml.toNextSelection();
347 					}
348 				}
349 			}
350 			
351 			if( result.size() > 0 )
352 			{
353 				targetProperty.setValue( targetXmlObject.xmlText( new XmlOptions().setSaveAggressiveNamespaces()) );
354 			}
355 			
356 			return result.toArray( new String[result.size()] );
357 		}
358 		finally
359 		{
360 			sourceXml.dispose();
361 			targetXml.dispose();
362 			
363 			if( lastSource != null )
364 				lastSource.dispose();
365 		}
366 	}
367 
368 	protected String [] transferStringToXml(TestStepProperty sourceProperty, TestStepProperty targetProperty, SubmitContext context) throws XmlException, Exception
369 	{
370 		XmlObject targetXml = XmlObject.Factory.parse( targetProperty.getValue() );
371 		XmlCursor targetCursor = targetXml.newCursor();
372 		
373 		try
374 		{
375 			List<String> result = new ArrayList<String>();
376 			
377 			targetCursor.selectPath( PropertyExpansionRequestFilter.expandProperties( context, 
378 					getTargetPath() ));
379 			
380 			if( !targetCursor.toNextSelection() )
381 				throw new Exception( "Missing match for Target path [" + getTargetPath() + "]" );
382 			
383 			String value = sourceProperty.getValue();
384 			
385 			Node targetNode = targetCursor.getDomNode();
386 			setNodeValue(value, targetNode);
387 			
388 			result.add( value );
389 			
390 			if( getTransferToAll() )
391 			{
392 				while( targetCursor.toNextSelection())
393 				{
394 					targetNode = targetCursor.getDomNode();
395 					setNodeValue(value, targetNode);
396 					
397 					result.add( value );
398 				}
399 			}
400 			
401 			targetProperty.setValue( targetXml.xmlText( new XmlOptions().setSaveAggressiveNamespaces()) );
402 			
403 			return result.toArray( new String[result.size()] );
404 		}
405 		finally
406 		{
407 			targetCursor.dispose();
408 		}
409 	}
410 
411 	private String setNodeValue(String value, Node node) throws Exception
412 	{
413 		short targetNodeType = node.getNodeType();
414 		
415 		if( targetNodeType == Node.DOCUMENT_FRAGMENT_NODE )
416 		{
417 			node = ((DocumentFragment) node ).getFirstChild();
418 			if( node != null )
419 				targetNodeType = node.getNodeType();
420 			else
421 				throw new Exception( "Missing source value for " + getSourcePropertyName() );
422 		}
423 		
424 		if( targetNodeType == Node.TEXT_NODE || targetNodeType == Node.ATTRIBUTE_NODE )
425 		{
426 			node.setNodeValue( value );
427 		}
428 		else if( targetNodeType == Node.ELEMENT_NODE )
429 		{
430 			XmlUtils.setElementText( (Element) node, value );
431 		}
432 		else
433 		{
434 			throw new Exception( "Failed to set value to node [" + node.toString() + "] of type [" + targetNodeType + "]" ); 
435 		}
436 		
437 		return value;
438 	}
439 
440 	protected String transferXmlToString( TestStepProperty sourceProperty, TestStepProperty targetProperty, SubmitContext context) throws XmlException, Exception
441 	{
442 		XmlObject sourceXml = XmlObject.Factory.parse( sourceProperty.getValue() );
443 		XmlCursor sourceCursor = sourceXml.newCursor();
444 		
445 		try
446 		{
447 			String value = null;
448 			
449 			sourceCursor.selectPath( PropertyExpansionRequestFilter.expandProperties( context, 
450 					getSourcePath()) );
451 			
452 			if( !sourceCursor.toNextSelection() )
453 			{
454 				if( !getSetNullOnMissingSource() && !getIgnoreEmpty() )
455 					throw new Exception( "Missing match for Source path [" + getSourcePath() + "]" );
456 			}
457 			else
458 			{
459 				Node sourceNode = sourceCursor.getDomNode();
460 				short sourceNodeType = sourceNode.getNodeType();
461 				
462 				if( sourceNodeType == Node.DOCUMENT_FRAGMENT_NODE )
463 				{
464 					sourceNode = ((DocumentFragment) sourceNode ).getFirstChild();
465 					if( sourceNode != null )
466 						sourceNodeType = sourceNode.getNodeType();
467 					else
468 						throw new Exception( "Missing source value for " + getSourcePropertyName() );
469 				}
470 				
471 				if( sourceNodeType == Node.TEXT_NODE || sourceNodeType == Node.ATTRIBUTE_NODE )
472 				{
473 					value = sourceNode.getNodeValue();
474 				}
475 				else if( sourceNodeType == Node.ELEMENT_NODE )
476 				{
477 					value = XmlUtils.getElementText( (Element) sourceNode );
478 				}
479 			}
480 			
481 			if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
482 				targetProperty.setValue( value );
483 			else
484 				value = "";
485 			
486 			return value;
487 		}
488 		finally
489 		{
490 			sourceCursor.dispose();
491 		}
492 	}
493 
494 	/***
495 	 * Method called for transferring between 2 xml properties..
496 	 */
497 	
498 	private String transferXmlValue(XmlCursor source, XmlCursor dest) throws Exception
499 	{
500 		// just copy if nodes are of same type
501 		Node destNode = dest.getDomNode();
502 		Node sourceNode = source.getDomNode();
503 		short destNodeType = destNode.getNodeType();
504 		short sourceNodeType = sourceNode.getNodeType();
505 		String value = null;
506 		
507 		if( sourceNodeType == Node.DOCUMENT_FRAGMENT_NODE )
508 		{
509 			sourceNode = ((DocumentFragment) sourceNode ).getFirstChild();
510 			if( sourceNode != null )
511 				sourceNodeType = sourceNode.getNodeType();
512 			else
513 				throw new Exception( "Missing source value for " + source );
514 		}
515 		
516 		// same type of node?
517 		if( destNodeType == sourceNodeType )
518 		{
519 			if( destNodeType == Node.TEXT_NODE || destNodeType == Node.ATTRIBUTE_NODE )
520 			{
521 				value = sourceNode.getNodeValue();
522 				if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
523 					destNode.setNodeValue( value );
524 			}
525 			else if( config.getTransferTextContent() && destNodeType == Node.ELEMENT_NODE )
526 			{
527 				value = XmlUtils.getElementText( (Element) sourceNode);
528 				if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
529 					XmlUtils.setElementText( (Element) destNode, value );
530 			}
531 			else
532 			{
533 				destNode = destNode.getParentNode().replaceChild( 
534 						destNode.getOwnerDocument().importNode( sourceNode, true ), destNode );
535 				
536 				value = dest.xmlText();
537 			}
538 		}
539 		// text to attribute?
540 		else if( (sourceNodeType == Node.TEXT_NODE && destNodeType == Node.ATTRIBUTE_NODE) ||
541 				(sourceNodeType == Node.ATTRIBUTE_NODE && destNodeType == Node.TEXT_NODE) )
542 		{
543 			value = sourceNode.getNodeValue();
544 			if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
545 				destNode.setNodeValue( value );
546 		}
547 		else if( sourceNodeType == Node.ELEMENT_NODE && 
548 				destNodeType == Node.ATTRIBUTE_NODE || destNodeType == Node.TEXT_NODE )
549 		{
550 			value = XmlUtils.getElementText( (Element) sourceNode );
551 			if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
552 				destNode.setNodeValue( value );
553 		}
554 		else if( destNodeType == Node.ELEMENT_NODE && 
555 				sourceNodeType == Node.ATTRIBUTE_NODE || sourceNodeType == Node.TEXT_NODE )
556 		{
557 			// hmm.. not sure xmlbeans handles this ok
558 			value = sourceNode.getNodeValue();
559 			if( !getIgnoreEmpty() || (value != null && value.length() > 0) )
560 				XmlUtils.setElementText( (Element) destNode, value );
561 		}
562 
563 		return value;
564 	}
565 	
566 	/***
567 	 * Returns the name of the source property. 
568 	 */
569 	
570 	public String getSourcePropertyName()
571 	{
572 		if( sourceType == null )
573 			return null;
574 		
575 		if( currentSourceProperty != null )
576 			return currentSourceProperty.getName();
577 		
578 		TestStep actualSourceStep = getSourceStep();
579 		if( actualSourceStep == null )
580 			return sourceType;
581 		
582 		TestStepProperty property = actualSourceStep.getProperty( sourceType );
583 		return property == null ? sourceType : property.getName();
584 	}
585 	
586 	public void setSourcePropertyName( String name )
587 	{
588 		String old = getSourcePropertyName();
589 		
590 		// check for change
591 		if( (name == null && old == null) || (name != null && old != null && name.equals( old ))) return;
592 
593 		// update
594 		sourceType = name;
595 		config.setSourceType( name );
596 		
597 		// update actual property
598 		TestStep sourceStep2 = getSourceStep();
599 		currentSourceProperty = sourceStep2 != null && sourceType != null ? 
600 				sourceStep2.getProperty( sourceType ) : null;
601 		
602 		// notify!
603 		propertyChangeSupport.firePropertyChange( SOURCE_TYPE_PROPERTY, old, name );
604 	}
605 	
606 	public TestStepProperty getTargetProperty()
607 	{
608 		if( targetType == null )
609 			return null;
610 		
611 		if( currentTargetProperty != null )
612 			return currentTargetProperty;
613 		
614 		TestStep actualTargetStep = getTargetStep();
615 		return actualTargetStep == null ? null : actualTargetStep.getProperty( targetType );
616 	}
617 	
618 	public String getTargetPropertyName()
619 	{
620 		if( targetType == null )
621 			return null;
622 		
623 		if( currentTargetProperty != null )
624 			return currentTargetProperty.getName();
625 		
626 		TestStep actualTargetStep = getTargetStep();
627 		TestStepProperty property = actualTargetStep == null ? null : actualTargetStep.getProperty( targetType );
628 		return actualTargetStep == null || property == null ? targetType: property.getName();
629 	}
630 	
631 	public void setTargetPropertyName( String name )
632 	{
633 		String old = getTargetPropertyName();
634 		
635 		// check for change
636 		if( (name == null && old == null) || (name != null && old != null && name.equals( old ))) return;
637 
638 		// update
639 		targetType = name;
640 		config.setTargetType( name );
641 		
642 		// update actual property
643 		TestStep targetStep2 = getTargetStep();
644 		
645 		currentTargetProperty = targetStep2 != null && targetType != null ? 
646 				targetStep2.getProperty( targetType ) : null;
647 		
648 		// notify!
649 		propertyChangeSupport.firePropertyChange( TARGET_TYPE_PROPERTY, old, name );
650 	}
651 	
652 	public String getName()
653 	{
654 		return config.getName();
655 	}
656 	
657 	public void setSourcePath( String path )
658 	{
659 		String old = sourcePath;
660 		sourcePath = path;
661 		config.setSourcePath( path );
662 		propertyChangeSupport.firePropertyChange( SOURCE_PATH_PROPERTY, old, path );
663 	}
664 	
665 	public void setTargetPath( String path )
666 	{
667 		String old = targetPath;
668 		targetPath = path;
669 		config.setTargetPath( path );
670 		propertyChangeSupport.firePropertyChange( TARGET_PATH_PROPERTY, old, path );
671 	}
672 	
673 	public void setName( String name )
674 	{
675 		String old = this.name;
676 		this.name = name;
677 		config.setName( name );
678 		propertyChangeSupport.firePropertyChange( NAME_PROPERTY, old, name );
679 	}
680 
681 	public TestStep getSourceStep()
682 	{
683 		String sourceStepName = getSourceStepName();
684 		return sourceStepName == null ? null : testCase.getTestStepByName( sourceStepName );
685 	}
686 
687 	public String getSourceStepName()
688 	{
689 		if( sourceStep != null )
690 			return sourceStep;
691 		
692 		if( testCase == null )
693 			return null;
694 		
695 		TestStep step = testCase.findPreviousStepOfType( this.testStep, WsdlTestRequestStep.class );
696 		return step == null ? null : step.getName();
697 	}
698 
699 	public void setSourceStepName(String sourceStep)
700 	{
701 		String old = getSourceStepName();
702 		
703 		//	 check for change
704 		if( (sourceStep == null && old == null) || (sourceStep != null && old != null && sourceStep.equals( old ))) return;
705 		
706 		if( sourceStep == null )
707 			log.debug( "Setting sourceStep for transfer [" + getName() + "] to null" );
708 		
709 		this.sourceStep = sourceStep;
710 		config.setSourceStep( sourceStep );
711 		
712 		if( currentSourceStep != null )
713 		{
714 			currentSourceStep.removePropertyChangeListener( stepNameChangeListener );
715 			((WsdlTestStep)currentSourceStep).removeTestStepListener( propertyNameChangeListener );
716 		}
717 		
718 		currentSourceStep = (WsdlTestStep) (sourceStep == null ? null : testStep.getTestCase().getTestStepByName( sourceStep ));
719 		if( currentSourceStep != null )
720 		{
721 			currentSourceStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
722 			((WsdlTestStep)currentSourceStep).addTestStepListener( propertyNameChangeListener );
723 		}
724 		
725 		propertyChangeSupport.firePropertyChange( SOURCE_STEP_PROPERTY, old, sourceStep );
726 		setSourcePropertyName( null );
727 	}
728 	
729 	public TestStep getTargetStep()
730 	{
731 		String targetStepName = getTargetStepName();
732 		return targetStepName == null ? null : testCase.getTestStepByName( targetStepName );
733 	}
734 
735 	public String getTargetStepName()
736 	{
737 		if( targetStep != null )
738 			return targetStep;
739 		
740 		if( testCase == null )
741 			return null;
742 		
743 		TestStep step = testCase.findNextStepOfType( this.testStep, WsdlTestRequestStep.class );
744 		return step == null ? null : step.getName();
745 	}
746 
747 	public void setTargetStepName(String targetStep)
748 	{
749 		String old = getTargetStepName();
750 		
751 		//	 check for change
752 		if( (targetStep == null && old == null) || (targetStep != null && old != null && targetStep.equals( old ))) return;
753 		
754 		if( targetStep == null )
755 			log.debug( "Setting targetStep for transfer [" + getName() + "] to null" );
756 		
757 		this.targetStep = targetStep;
758 		config.setTargetStep( targetStep );
759 		
760 		if( currentTargetStep != null )
761 		{
762 			currentTargetStep.removePropertyChangeListener( stepNameChangeListener );
763 			((WsdlTestStep)currentTargetStep).removeTestStepListener( propertyNameChangeListener );
764 		}
765 		
766 		currentTargetStep = (WsdlTestStep) (targetStep == null ? null : testStep.getTestCase().getTestStepByName( targetStep ));
767 		if( currentTargetStep != null )
768 		{
769 			currentTargetStep.addPropertyChangeListener( TestStep.NAME_PROPERTY, stepNameChangeListener );
770 			((WsdlTestStep)currentTargetStep).addTestStepListener( propertyNameChangeListener );
771 		}
772 		
773 		propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, old, targetStep );
774 		setTargetPropertyName( null );
775 	}
776 
777 	public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener)
778 	{
779 		propertyChangeSupport.addPropertyChangeListener( propertyName, listener );
780 	}
781 
782 	public void addPropertyChangeListener(PropertyChangeListener listener)
783 	{
784 		propertyChangeSupport.addPropertyChangeListener( listener );
785 	}
786 
787 	public void removePropertyChangeListener(PropertyChangeListener listener)
788 	{
789 		propertyChangeSupport.removePropertyChangeListener( listener );
790 	}
791 
792 	public void removePropertyChangeListener(String propertyName, PropertyChangeListener listener)
793 	{
794 		propertyChangeSupport.removePropertyChangeListener( propertyName, listener );
795 	}
796 	
797 	public boolean getFailOnError()
798 	{
799 		return config.getFailOnError();
800 	}
801 	
802 	public void setFailOnError( boolean failOnError )
803 	{
804 		config.setFailOnError( failOnError );
805 	}
806 	
807 	public boolean getTransferToAll()
808 	{
809 		return config.getTransferToAll();
810 	}
811 	
812 	public void setTransferToAll( boolean transferToAll )
813 	{
814 		config.setTransferToAll( transferToAll );
815 	}
816 	
817 	public boolean getIgnoreEmpty()
818 	{
819 		return config.getIgnoreEmpty();
820 	}
821 	
822 	public void setIgnoreEmpty( boolean ignoreEmpty )
823 	{
824 		config.setIgnoreEmpty( ignoreEmpty );
825 	}
826 	
827 	public boolean getSetNullOnMissingSource()
828 	{
829 		return config.getSetNullOnMissingSource();
830 	}
831 	
832 	public void setSetNullOnMissingSource( boolean setNullOnMissingSource )
833 	{
834 		config.setSetNullOnMissingSource( setNullOnMissingSource );
835 	}
836 	
837 	public boolean getTransferTextContent()
838 	{
839 		return config.getTransferTextContent();
840 	}
841 	
842 	public void setTransferTextContent( boolean transferTextContent )
843 	{
844 		config.setTransferTextContent( transferTextContent );
845 	}
846 	
847 	private final class InternalTestSuiteListener extends TestSuiteListenerAdapter
848 	{
849 		public void testStepRemoved(TestStep testStep, int index)
850 		{
851 			if( testStep.getTestCase() == testCase )
852 			{
853 				String stepName = testStep.getName();
854 				if( stepName.equals( sourceStep ) )
855 				{
856 					setSourceStepName( null );
857 				}
858 			
859 				if( stepName.equals( targetStep ) )
860 				{
861 					setTargetStepName( null );
862 				}
863 			}
864 		}
865 	}
866 
867 	/***
868 	 * Handle changes to source/target testStep names
869 	 * 
870 	 * @author Ole.Matzura
871 	 */
872 	
873 	private class StepNameChangeListener implements PropertyChangeListener
874 	{
875 		public void propertyChange(PropertyChangeEvent evt)
876 		{
877 			String oldName = (String) evt.getOldValue();
878 			String newValue = (String) evt.getNewValue();
879 			
880 			if( newValue == null )
881 			{
882 				log.error( "Tried to change stepname to null!" );
883 				Thread.dumpStack();
884 				return;
885 			}
886 			
887 			if( oldName.equals( sourceStep ))
888 			{
889 				sourceStep = newValue;
890 				config.setSourceStep( sourceStep );
891 				propertyChangeSupport.firePropertyChange( SOURCE_STEP_PROPERTY, oldName, sourceStep );
892 			}
893 			
894 			if( oldName.equals( targetStep ))
895 			{
896 				targetStep = newValue;
897 				config.setTargetStep( targetStep );
898 				propertyChangeSupport.firePropertyChange( TARGET_STEP_PROPERTY, oldName, targetStep );
899 			}
900 		}
901 	}
902 	
903 	/***
904 	 * Handle changes to source/target property names
905 	 * 
906 	 * @author Ole.Matzura
907 	 */
908 	
909 	private class PropertyNameChangeListener extends WsdlTestStepListenerAdapter
910 	{
911 		public void propertyRenamed(String oldName, String newName)
912 		{
913 			if( oldName.equals( sourceType ))
914 			{
915 				sourceType = newName;
916 				config.setSourceType( sourceType );
917 				propertyChangeSupport.firePropertyChange( SOURCE_TYPE_PROPERTY, oldName, sourceType );
918 			}
919 			
920 			if( oldName.equals( targetType ))
921 			{
922 				targetType = newName;
923 				config.setTargetType( targetType );
924 				propertyChangeSupport.firePropertyChange( TARGET_TYPE_PROPERTY, oldName, targetType );
925 			}
926 		}
927 
928 		public void propertyRemoved(String name)
929 		{
930 			if( name.equals( sourceType ))
931 			{
932 				log.warn( "source property for transfer [" + getName() + "] in teststep [" + 
933 						testStep.getName() + "] set to null, was [" + name + "]" );  
934 				
935 				setSourcePropertyName( null );
936 			}
937 
938 			if( name.equals( targetType ))
939 			{
940 				log.warn( "target property for transfer [" + getName() + "] in teststep [" + 
941 						testStep.getName() + "] set to null, was [" + name + "]" );  
942 				
943 				setTargetPropertyName( null );
944 			}
945 		}
946 	}
947 }