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