View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2010 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.assertions.basic;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Dimension;
17  import java.awt.event.ActionEvent;
18  import java.awt.event.WindowAdapter;
19  import java.awt.event.WindowEvent;
20  import java.util.ArrayList;
21  import java.util.List;
22  
23  import javax.swing.AbstractAction;
24  import javax.swing.Action;
25  import javax.swing.BorderFactory;
26  import javax.swing.JButton;
27  import javax.swing.JCheckBox;
28  import javax.swing.JDialog;
29  import javax.swing.JPanel;
30  import javax.swing.JScrollPane;
31  import javax.swing.JSplitPane;
32  import javax.swing.JTextArea;
33  import javax.swing.SwingUtilities;
34  
35  import junit.framework.ComparisonFailure;
36  
37  import org.apache.log4j.Logger;
38  import org.apache.xmlbeans.XmlAnySimpleType;
39  import org.apache.xmlbeans.XmlCursor;
40  import org.apache.xmlbeans.XmlObject;
41  import org.apache.xmlbeans.XmlOptions;
42  import org.apache.xmlbeans.XmlQName;
43  import org.apache.xmlbeans.impl.values.XmlValueDisconnectedException;
44  import org.custommonkey.xmlunit.Diff;
45  import org.custommonkey.xmlunit.Difference;
46  import org.custommonkey.xmlunit.DifferenceEngine;
47  import org.custommonkey.xmlunit.DifferenceListener;
48  import org.custommonkey.xmlunit.XMLAssert;
49  import org.w3c.dom.Attr;
50  import org.w3c.dom.Element;
51  import org.w3c.dom.Node;
52  
53  import com.eviware.soapui.SoapUI;
54  import com.eviware.soapui.config.TestAssertionConfig;
55  import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
56  import com.eviware.soapui.impl.wsdl.WsdlInterface;
57  import com.eviware.soapui.impl.wsdl.support.HelpUrls;
58  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathImpl;
59  import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
60  import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
61  import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion;
62  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
63  import com.eviware.soapui.impl.wsdl.teststeps.assertions.AbstractTestAssertionFactory;
64  import com.eviware.soapui.model.TestModelItem;
65  import com.eviware.soapui.model.iface.MessageExchange;
66  import com.eviware.soapui.model.iface.SubmitContext;
67  import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
68  import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
69  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
70  import com.eviware.soapui.model.support.XPathReference;
71  import com.eviware.soapui.model.support.XPathReferenceContainer;
72  import com.eviware.soapui.model.support.XPathReferenceImpl;
73  import com.eviware.soapui.model.testsuite.Assertable;
74  import com.eviware.soapui.model.testsuite.AssertionError;
75  import com.eviware.soapui.model.testsuite.AssertionException;
76  import com.eviware.soapui.model.testsuite.RequestAssertion;
77  import com.eviware.soapui.model.testsuite.ResponseAssertion;
78  import com.eviware.soapui.model.testsuite.TestProperty;
79  import com.eviware.soapui.model.testsuite.TestStep;
80  import com.eviware.soapui.support.StringUtils;
81  import com.eviware.soapui.support.UISupport;
82  import com.eviware.soapui.support.components.JUndoableTextArea;
83  import com.eviware.soapui.support.components.JXToolBar;
84  import com.eviware.soapui.support.types.StringList;
85  import com.eviware.soapui.support.xml.XmlObjectConfigurationBuilder;
86  import com.eviware.soapui.support.xml.XmlObjectConfigurationReader;
87  import com.eviware.soapui.support.xml.XmlUtils;
88  import com.jgoodies.forms.builder.ButtonBarBuilder;
89  
90  /***
91   * Assertion that matches a specified XPath expression and its expected result
92   * against the associated WsdlTestRequests response message
93   * 
94   * @author Ole.Matzura
95   */
96  
97  public class XPathContainsAssertion extends WsdlMessageAssertion implements RequestAssertion, ResponseAssertion,
98  		XPathReferenceContainer
99  {
100 	private final static Logger log = Logger.getLogger( XPathContainsAssertion.class );
101 	private String expectedContent;
102 	private String path;
103 	private JDialog configurationDialog;
104 	private JTextArea pathArea;
105 	private JTextArea contentArea;
106 	private boolean configureResult;
107 	private boolean allowWildcards;
108 	private boolean ignoreNamespaceDifferences;
109 
110 	public static final String ID = "XPath Match";
111 	public static final String LABEL = "XPath Match";
112 	private JCheckBox allowWildcardsCheckBox;
113 	private JCheckBox ignoreNamespaceDifferencesCheckBox;
114 
115 	public XPathContainsAssertion( TestAssertionConfig assertionConfig, Assertable assertable )
116 	{
117 		super( assertionConfig, assertable, true, true, true, true );
118 
119 		XmlObjectConfigurationReader reader = new XmlObjectConfigurationReader( getConfiguration() );
120 		path = reader.readString( "path", null );
121 		expectedContent = reader.readString( "content", null );
122 		allowWildcards = reader.readBoolean( "allowWildcards", false );
123 		ignoreNamespaceDifferences = reader.readBoolean( "ignoreNamspaceDifferences", false );
124 	}
125 
126 	public String getExpectedContent()
127 	{
128 		return expectedContent;
129 	}
130 
131 	public void setExpectedContent( String expectedContent )
132 	{
133 		this.expectedContent = expectedContent;
134 		setConfiguration( createConfiguration() );
135 	}
136 
137 	/***
138 	 * @deprecated
139 	 */
140 
141 	@Deprecated
142 	public void setContent( String content )
143 	{
144 		setExpectedContent( content );
145 	}
146 
147 	public String getPath()
148 	{
149 		return path;
150 	}
151 
152 	public void setPath( String path )
153 	{
154 		this.path = path;
155 		setConfiguration( createConfiguration() );
156 	}
157 
158 	public boolean isAllowWildcards()
159 	{
160 		return allowWildcards;
161 	}
162 
163 	public void setAllowWildcards( boolean allowWildcards )
164 	{
165 		this.allowWildcards = allowWildcards;
166 		setConfiguration( createConfiguration() );
167 	}
168 
169 	public boolean isIgnoreNamespaceDifferences()
170 	{
171 		return ignoreNamespaceDifferences;
172 	}
173 
174 	public void setIgnoreNamespaceDifferences( boolean ignoreNamespaceDifferences )
175 	{
176 		this.ignoreNamespaceDifferences = ignoreNamespaceDifferences;
177 		setConfiguration( createConfiguration() );
178 	}
179 
180 	@Override
181 	protected String internalAssertResponse( MessageExchange messageExchange, SubmitContext context )
182 			throws AssertionException
183 	{
184 		if( !messageExchange.hasResponse() )
185 			return "Missing Response";
186 		else
187 			return assertContent( messageExchange.getResponseContentAsXml(), context, "Response" );
188 	}
189 
190 	public String assertContent( String response, SubmitContext context, String type ) throws AssertionException
191 	{
192 		try
193 		{
194 			if( path == null )
195 				return "Missing path for XPath assertion";
196 			if( expectedContent == null )
197 				return "Missing content for XPath assertion";
198 
199 			XmlObject xml = XmlObject.Factory.parse( response );
200 			String expandedPath = PropertyExpander.expandProperties( context, path );
201 			XmlObject[] items = xml.selectPath( expandedPath );
202 			AssertedXPathsContainer assertedXPathsContainer = ( AssertedXPathsContainer )context
203 					.getProperty( AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY );
204 
205 			XmlObject contentObj = null;
206 			String expandedContent = PropertyExpander.expandProperties( context, expectedContent );
207 
208 			// stupid check for text selection for those situation that the
209 			// selected
210 			// text actually contains xml which should be compared as a string.
211 			if( !expandedPath.endsWith( "text()" ) )
212 			{
213 				try
214 				{
215 					contentObj = XmlObject.Factory.parse( expandedContent );
216 				}
217 				catch( Exception e )
218 				{
219 					// this is ok.. it just means that the content to match is not
220 					// xml
221 					// but
222 					// (hopefully) just a string
223 				}
224 			}
225 
226 			if( items.length == 0 )
227 				throw new Exception( "Missing content for xpath [" + path + "] in " + type );
228 
229 			XmlOptions options = new XmlOptions();
230 			options.setSavePrettyPrint();
231 			options.setSaveOuter();
232 
233 			for( int c = 0; c < items.length; c++ )
234 			{
235 				try
236 				{
237 					AssertedXPathImpl assertedXPathImpl = null;
238 					if( assertedXPathsContainer != null )
239 					{
240 						String xpath = XmlUtils.createAbsoluteXPath( items[c].getDomNode() );
241 						if( xpath != null )
242 						{
243 							XmlObject xmlObj = items[c]; // XmlObject.Factory.parse(
244 							// items[c].xmlText( options
245 							// ) );
246 
247 							assertedXPathImpl = new AssertedXPathImpl( this, xpath, xmlObj );
248 							assertedXPathsContainer.addAssertedXPath( assertedXPathImpl );
249 						}
250 					}
251 
252 					if( contentObj == null )
253 					{
254 						if( items[c] instanceof XmlAnySimpleType && !( items[c] instanceof XmlQName ) )
255 						{
256 							String value = ( ( XmlAnySimpleType )items[c] ).getStringValue();
257 							String expandedValue = PropertyExpander.expandProperties( context, value );
258 							XMLAssert.assertEquals( expandedContent, expandedValue );
259 						}
260 						else
261 						{
262 							Node domNode = items[c].getDomNode();
263 							if( domNode.getNodeType() == Node.ELEMENT_NODE )
264 							{
265 								String expandedValue = PropertyExpander.expandProperties( context, XmlUtils
266 										.getElementText( ( Element )domNode ) );
267 								XMLAssert.assertEquals( expandedContent, expandedValue );
268 							}
269 							else
270 							{
271 								String expandedValue = PropertyExpander.expandProperties( context, domNode.getNodeValue() );
272 								XMLAssert.assertEquals( expandedContent, expandedValue );
273 							}
274 						}
275 					}
276 					else
277 					{
278 						compareValues( contentObj.xmlText( options ), items[c].xmlText( options ), items[c] );
279 					}
280 
281 					break;
282 				}
283 				catch( Throwable e )
284 				{
285 					if( c == items.length - 1 )
286 						throw e;
287 				}
288 			}
289 		}
290 		catch( Throwable e )
291 		{
292 			String msg = "";
293 
294 			if( e instanceof ComparisonFailure )
295 			{
296 				ComparisonFailure cf = ( ComparisonFailure )e;
297 				String expected = cf.getExpected();
298 				String actual = cf.getActual();
299 
300 				// if( expected.length() > ERROR_LENGTH_LIMIT )
301 				// expected = expected.substring(0, ERROR_LENGTH_LIMIT) + "..";
302 				//				
303 				// if( actual.length() > ERROR_LENGTH_LIMIT )
304 				// actual = actual.substring(0, ERROR_LENGTH_LIMIT) + "..";
305 
306 				msg = "XPathContains comparison failed, expecting [" + expected + "], actual was [" + actual + "]";
307 			}
308 			else
309 			{
310 				msg = "XPathContains assertion failed for path [" + path + "] : " + e.getClass().getSimpleName() + ":"
311 						+ e.getMessage();
312 			}
313 
314 			throw new AssertionException( new AssertionError( msg ) );
315 		}
316 
317 		return type + " matches content for [" + path + "]";
318 	}
319 
320 	private void compareValues( String expandedContent, String expandedValue, XmlObject object ) throws Exception
321 	{
322 		Diff diff = new Diff( expandedContent, expandedValue );
323 		InternalDifferenceListener internalDifferenceListener = new InternalDifferenceListener();
324 		diff.overrideDifferenceListener( internalDifferenceListener );
325 
326 		if( !diff.identical() )
327 			throw new Exception( diff.toString() );
328 
329 		StringList nodesToRemove = internalDifferenceListener.getNodesToRemove();
330 
331 		if( !nodesToRemove.isEmpty() )
332 		{
333 			for( String node : nodesToRemove )
334 			{
335 				if( node == null )
336 					continue;
337 
338 				int ix = node.indexOf( "\n/" );
339 				if( ix != -1 )
340 					node = node.substring( 0, ix + 1 ) + "./" + node.substring( ix + 1 );
341 				else if( node.startsWith( "/" ) )
342 					node = "/" + node;
343 
344 				XmlObject[] paths = object.selectPath( node );
345 				if( paths.length > 0 )
346 				{
347 					Node domNode = paths[0].getDomNode();
348 					if( domNode.getNodeType() == Node.ATTRIBUTE_NODE )
349 						( ( Attr )domNode ).getOwnerElement().removeAttributeNode( ( Attr )domNode );
350 					else
351 						domNode.getParentNode().removeChild( domNode );
352 
353 					try
354 					{
355 						object.set( object.copy() );
356 					}
357 					catch( XmlValueDisconnectedException e )
358 					{
359 						// this means that we've excluded the root note.. it's ok..
360 						return;
361 					}
362 				}
363 			}
364 		}
365 	}
366 
367 	@Override
368 	public boolean configure()
369 	{
370 		if( configurationDialog == null )
371 			buildConfigurationDialog();
372 
373 		pathArea.setText( path );
374 		contentArea.setText( expectedContent );
375 		allowWildcardsCheckBox.setSelected( allowWildcards );
376 		ignoreNamespaceDifferencesCheckBox.setSelected( ignoreNamespaceDifferences );
377 
378 		UISupport.showDialog( configurationDialog );
379 		return configureResult;
380 	}
381 
382 	protected void buildConfigurationDialog()
383 	{
384 		configurationDialog = new JDialog( UISupport.getMainFrame() );
385 		configurationDialog.setTitle( "XPath Match configuration" );
386 		configurationDialog.addWindowListener( new WindowAdapter()
387 		{
388 			@Override
389 			public void windowOpened( WindowEvent event )
390 			{
391 				SwingUtilities.invokeLater( new Runnable()
392 				{
393 					public void run()
394 					{
395 						pathArea.requestFocusInWindow();
396 					}
397 				} );
398 			}
399 		} );
400 
401 		JPanel contentPanel = new JPanel( new BorderLayout() );
402 		contentPanel.add( UISupport.buildDescription( "Specify xpath expression and expected result",
403 				"declare namespaces with <code>declare namespace &lt;prefix&gt;='&lt;namespace&gt;';</code>", null ),
404 				BorderLayout.NORTH );
405 
406 		JSplitPane splitPane = UISupport.createVerticalSplit();
407 
408 		pathArea = new JUndoableTextArea();
409 		pathArea.setToolTipText( "Specifies the XPath expression to select from the message for validation" );
410 
411 		JPanel pathPanel = new JPanel( new BorderLayout() );
412 		JXToolBar pathToolbar = UISupport.createToolbar();
413 		addPathEditorActions( pathToolbar );
414 
415 		pathPanel.add( pathToolbar, BorderLayout.NORTH );
416 		pathPanel.add( new JScrollPane( pathArea ), BorderLayout.CENTER );
417 
418 		splitPane.setTopComponent( UISupport.addTitledBorder( pathPanel, "XPath Expression" ) );
419 
420 		contentArea = new JUndoableTextArea();
421 		contentArea.setToolTipText( "Specifies the expected result of the XPath expression" );
422 
423 		JPanel matchPanel = new JPanel( new BorderLayout() );
424 		JXToolBar contentToolbar = UISupport.createToolbar();
425 		addMatchEditorActions( contentToolbar );
426 
427 		matchPanel.add( contentToolbar, BorderLayout.NORTH );
428 		matchPanel.add( new JScrollPane( contentArea ), BorderLayout.CENTER );
429 
430 		splitPane.setBottomComponent( UISupport.addTitledBorder( matchPanel, "Expected Result" ) );
431 		splitPane.setDividerLocation( 150 );
432 		splitPane.setBorder( BorderFactory.createEmptyBorder( 0, 1, 0, 1 ) );
433 
434 		contentPanel.add( splitPane, BorderLayout.CENTER );
435 
436 		ButtonBarBuilder builder = new ButtonBarBuilder();
437 
438 		ShowOnlineHelpAction showOnlineHelpAction = new ShowOnlineHelpAction( HelpUrls.XPATHASSERTIONEDITOR_HELP_URL );
439 		builder.addFixed( UISupport.createToolbarButton( showOnlineHelpAction ) );
440 		builder.addGlue();
441 
442 		JButton okButton = new JButton( new OkAction() );
443 		builder.addFixed( okButton );
444 		builder.addRelatedGap();
445 		builder.addFixed( new JButton( new CancelAction() ) );
446 
447 		builder.setBorder( BorderFactory.createEmptyBorder( 1, 5, 5, 5 ) );
448 
449 		contentPanel.add( builder.getPanel(), BorderLayout.SOUTH );
450 
451 		configurationDialog.setContentPane( contentPanel );
452 		configurationDialog.setSize( 600, 500 );
453 		configurationDialog.setModal( true );
454 		UISupport.initDialogActions( configurationDialog, showOnlineHelpAction, okButton );
455 	}
456 
457 	protected void addPathEditorActions( JXToolBar toolbar )
458 	{
459 		toolbar.addFixed( new JButton( new DeclareNamespacesFromCurrentAction() ) );
460 	}
461 
462 	protected void addMatchEditorActions( JXToolBar toolbar )
463 	{
464 		toolbar.addFixed( new JButton( new SelectFromCurrentAction() ) );
465 		toolbar.addRelatedGap();
466 		toolbar.addFixed( new JButton( new TestPathAction() ) );
467 		allowWildcardsCheckBox = new JCheckBox( "Allow Wildcards" );
468 
469 		Dimension dim = new Dimension( 100, 20 );
470 
471 		allowWildcardsCheckBox.setSize( dim );
472 		allowWildcardsCheckBox.setPreferredSize( dim );
473 
474 		allowWildcardsCheckBox.setOpaque( false );
475 		toolbar.addRelatedGap();
476 		toolbar.addFixed( allowWildcardsCheckBox );
477 
478 		Dimension largerDim = new Dimension( 200, 20 );
479 		ignoreNamespaceDifferencesCheckBox = new JCheckBox( "Ignore namespace prefixes" );
480 		ignoreNamespaceDifferencesCheckBox.setSize( largerDim );
481 		ignoreNamespaceDifferencesCheckBox.setPreferredSize( largerDim );
482 		ignoreNamespaceDifferencesCheckBox.setOpaque( false );
483 		toolbar.addRelatedGap();
484 		toolbar.addFixed( ignoreNamespaceDifferencesCheckBox );
485 	}
486 
487 	public XmlObject createConfiguration()
488 	{
489 		XmlObjectConfigurationBuilder builder = new XmlObjectConfigurationBuilder();
490 		builder.add( "path", path );
491 		builder.add( "content", expectedContent );
492 		builder.add( "allowWildcards", allowWildcards );
493 		builder.add( "ignoreNamspaceDifferences", ignoreNamespaceDifferences );
494 		return builder.finish();
495 	}
496 
497 	public void selectFromCurrent()
498 	{
499 		XmlCursor cursor = null;
500 
501 		try
502 		{
503 			String assertableContent = getAssertable().getAssertableContent();
504 			if( assertableContent == null || assertableContent.trim().length() == 0 )
505 			{
506 				UISupport.showErrorMessage( "Missing content to select from" );
507 				return;
508 			}
509 
510 			XmlObject xml = XmlObject.Factory.parse( assertableContent );
511 
512 			String txt = pathArea == null || !pathArea.isVisible() ? getPath() : pathArea.getSelectedText();
513 			if( txt == null )
514 				txt = pathArea == null ? "" : pathArea.getText();
515 
516 			WsdlTestRunContext context = new WsdlTestRunContext( ( TestStep )getAssertable().getModelItem() );
517 
518 			String expandedPath = PropertyExpander.expandProperties( context, txt.trim() );
519 
520 			if( contentArea != null && contentArea.isVisible() )
521 				contentArea.setText( "" );
522 
523 			cursor = xml.newCursor();
524 			cursor.selectPath( expandedPath );
525 			if( !cursor.toNextSelection() )
526 			{
527 				UISupport.showErrorMessage( "No match in current response" );
528 			}
529 			else if( cursor.hasNextSelection() )
530 			{
531 				UISupport.showErrorMessage( "More than one match in current response" );
532 			}
533 			else
534 			{
535 				String stringValue = XmlUtils.getValueForMatch( cursor );
536 
537 				if( contentArea != null && contentArea.isVisible() )
538 					contentArea.setText( stringValue );
539 				else
540 					setExpectedContent( stringValue );
541 			}
542 		}
543 		catch( Throwable e )
544 		{
545 			UISupport.showErrorMessage( e.toString() );
546 			SoapUI.logError( e );
547 		}
548 		finally
549 		{
550 			if( cursor != null )
551 				cursor.dispose();
552 		}
553 	}
554 
555 	private final class InternalDifferenceListener implements DifferenceListener
556 	{
557 		private StringList nodesToRemove = new StringList();
558 
559 		public int differenceFound( Difference diff )
560 		{
561 			if( allowWildcards
562 					&& ( diff.getId() == DifferenceEngine.TEXT_VALUE.getId() || diff.getId() == DifferenceEngine.ATTR_VALUE
563 							.getId() ) )
564 			{
565 				if( diff.getControlNodeDetail().getValue().equals( "*" ) )
566 				{
567 					Node node = diff.getTestNodeDetail().getNode();
568 					String xp = XmlUtils.createAbsoluteXPath( node.getNodeType() == Node.ATTRIBUTE_NODE ? node : node
569 							.getParentNode() );
570 					nodesToRemove.add( xp );
571 					return Diff.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
572 				}
573 			}
574 			else if( ignoreNamespaceDifferences && diff.getId() == DifferenceEngine.NAMESPACE_PREFIX_ID )
575 			{
576 				return Diff.RETURN_IGNORE_DIFFERENCE_NODES_IDENTICAL;
577 			}
578 
579 			return Diff.RETURN_ACCEPT_DIFFERENCE;
580 		}
581 
582 		public void skippedComparison( Node arg0, Node arg1 )
583 		{
584 
585 		}
586 
587 		public StringList getNodesToRemove()
588 		{
589 			return nodesToRemove;
590 		}
591 	}
592 
593 	public class OkAction extends AbstractAction
594 	{
595 		public OkAction()
596 		{
597 			super( "Save" );
598 		}
599 
600 		public void actionPerformed( ActionEvent arg0 )
601 		{
602 			setPath( pathArea.getText().trim() );
603 			setExpectedContent( contentArea.getText() );
604 			setAllowWildcards( allowWildcardsCheckBox.isSelected() );
605 			setIgnoreNamespaceDifferences( ignoreNamespaceDifferencesCheckBox.isSelected() );
606 			setConfiguration( createConfiguration() );
607 			configureResult = true;
608 			configurationDialog.setVisible( false );
609 		}
610 	}
611 
612 	public class CancelAction extends AbstractAction
613 	{
614 		public CancelAction()
615 		{
616 			super( "Cancel" );
617 		}
618 
619 		public void actionPerformed( ActionEvent arg0 )
620 		{
621 			configureResult = false;
622 			configurationDialog.setVisible( false );
623 		}
624 	}
625 
626 	public class DeclareNamespacesFromCurrentAction extends AbstractAction
627 	{
628 		public DeclareNamespacesFromCurrentAction()
629 		{
630 			super( "Declare" );
631 			putValue( Action.SHORT_DESCRIPTION, "Add namespace declaration from current message to XPath expression" );
632 		}
633 
634 		public void actionPerformed( ActionEvent arg0 )
635 		{
636 			try
637 			{
638 				String content = getAssertable().getAssertableContent();
639 				if( content != null && content.trim().length() > 0 )
640 				{
641 					pathArea.setText( XmlUtils.declareXPathNamespaces( content ) + pathArea.getText() );
642 				}
643 				else if( UISupport.confirm( "Declare namespaces from schema instead?", "Missing Response" ) )
644 				{
645 					pathArea.setText( XmlUtils.declareXPathNamespaces( ( WsdlInterface )getAssertable().getInterface() )
646 							+ pathArea.getText() );
647 				}
648 			}
649 			catch( Exception e )
650 			{
651 				log.error( e.getMessage() );
652 			}
653 		}
654 	}
655 
656 	public class TestPathAction extends AbstractAction
657 	{
658 		public TestPathAction()
659 		{
660 			super( "Test" );
661 			putValue( Action.SHORT_DESCRIPTION,
662 					"Tests the XPath expression for the current message against the Expected Content field" );
663 		}
664 
665 		public void actionPerformed( ActionEvent arg0 )
666 		{
667 			String oldPath = getPath();
668 			String oldContent = getExpectedContent();
669 			boolean oldAllowWildcards = isAllowWildcards();
670 
671 			setPath( pathArea.getText().trim() );
672 			setExpectedContent( contentArea.getText() );
673 			setAllowWildcards( allowWildcardsCheckBox.isSelected() );
674 			setIgnoreNamespaceDifferences( ignoreNamespaceDifferencesCheckBox.isSelected() );
675 
676 			try
677 			{
678 				String msg = assertContent( getAssertable().getAssertableContent(), new WsdlTestRunContext(
679 						( TestStep )getAssertable().getModelItem() ), "Response" );
680 				UISupport.showInfoMessage( msg, "Success" );
681 			}
682 			catch( AssertionException e )
683 			{
684 				UISupport.showErrorMessage( e.getMessage() );
685 			}
686 
687 			setPath( oldPath );
688 			setExpectedContent( oldContent );
689 			setAllowWildcards( oldAllowWildcards );
690 		}
691 	}
692 
693 	public class SelectFromCurrentAction extends AbstractAction
694 	{
695 		public SelectFromCurrentAction()
696 		{
697 			super( "Select from current" );
698 			putValue( Action.SHORT_DESCRIPTION,
699 					"Selects the XPath expression from the current message into the Expected Content field" );
700 		}
701 
702 		public void actionPerformed( ActionEvent arg0 )
703 		{
704 			selectFromCurrent();
705 		}
706 	}
707 
708 	@Override
709 	protected String internalAssertRequest( MessageExchange messageExchange, SubmitContext context )
710 			throws AssertionException
711 	{
712 		if( !messageExchange.hasRequest( true ) )
713 			return "Missing Request";
714 		else
715 			return assertContent( messageExchange.getRequestContent(), context, "Request" );
716 	}
717 
718 	public JTextArea getContentArea()
719 	{
720 		return contentArea;
721 	}
722 
723 	public JTextArea getPathArea()
724 	{
725 		return pathArea;
726 	}
727 
728 	@Override
729 	public PropertyExpansion[] getPropertyExpansions()
730 	{
731 		List<PropertyExpansion> result = new ArrayList<PropertyExpansion>();
732 
733 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( getAssertable().getModelItem(), this,
734 				"expectedContent" ) );
735 		result.addAll( PropertyExpansionUtils.extractPropertyExpansions( getAssertable().getModelItem(), this, "path" ) );
736 
737 		return result.toArray( new PropertyExpansion[result.size()] );
738 	}
739 
740 	public XPathReference[] getXPathReferences()
741 	{
742 		List<XPathReference> result = new ArrayList<XPathReference>();
743 
744 		if( StringUtils.hasContent( getPath() ) )
745 		{
746 			TestModelItem testStep = ( TestModelItem )getAssertable().getModelItem();
747 			TestProperty property = testStep instanceof WsdlTestRequestStep ? testStep.getProperty( "Response" )
748 					: testStep.getProperty( "Request" );
749 			result.add( new XPathReferenceImpl( "XPath for " + getName() + " XPathContainsAssertion in "
750 					+ testStep.getName(), property, this, "path" ) );
751 		}
752 
753 		return result.toArray( new XPathReference[result.size()] );
754 	}
755 
756 	public static class Factory extends AbstractTestAssertionFactory
757 	{
758 		public Factory()
759 		{
760 			super( XPathContainsAssertion.ID, XPathContainsAssertion.LABEL, XPathContainsAssertion.class );
761 		}
762 
763 		@Override
764 		public Class<? extends WsdlMessageAssertion> getAssertionClassType()
765 		{
766 			return XPathContainsAssertion.class;
767 		}
768 	}
769 }