View Javadoc

1   /*
2    *  soapui, copyright (C) 2005 Ole Matzura / eviware.com 
3    *
4    *  SoapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of the GNU Lesser General Public License as published by the Free Software Foundation; 
6    *  either version 2.1 of the License, or (at your option) any later version.
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;
14  
15  import java.awt.BorderLayout;
16  import java.awt.event.ActionEvent;
17  
18  import javax.swing.AbstractAction;
19  import javax.swing.Action;
20  import javax.swing.BorderFactory;
21  import javax.swing.JButton;
22  import javax.swing.JDialog;
23  import javax.swing.JLabel;
24  import javax.swing.JOptionPane;
25  import javax.swing.JPanel;
26  import javax.swing.JScrollPane;
27  import javax.swing.JSplitPane;
28  import javax.swing.JTextArea;
29  
30  import org.apache.log4j.Logger;
31  import org.apache.xmlbeans.XmlAnySimpleType;
32  import org.apache.xmlbeans.XmlCursor;
33  import org.apache.xmlbeans.XmlObject;
34  import org.apache.xmlbeans.XmlOptions;
35  import org.custommonkey.xmlunit.XMLAssert;
36  import org.w3c.dom.Element;
37  import org.w3c.dom.Node;
38  
39  import com.eviware.soapui.SoapUI;
40  import com.eviware.soapui.config.RequestAssertionConfig;
41  import com.eviware.soapui.impl.wsdl.teststeps.WsdlAssertion;
42  import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
43  import com.eviware.soapui.support.UISupport;
44  import com.eviware.soapui.support.XmlUtils;
45  import com.jgoodies.forms.builder.ButtonBarBuilder;
46  
47  /***
48   * Assertion that matches a specified XPath expression and its expected result against
49   * the associated WsdlTestRequests response message
50   * 
51   * @author Ole.Matzura
52   */
53  
54  public class XPathContainsAssertion extends WsdlAssertion
55  {
56  	private final static Logger log = Logger.getLogger( XPathContainsAssertion.class );
57  	private String content;
58     private String path;
59  	private JDialog configurationDialog;
60  	private JTextArea pathArea;
61  	private JTextArea contentArea;
62  
63     public XPathContainsAssertion(RequestAssertionConfig assertionConfig, WsdlTestRequest request)
64     {
65        super(assertionConfig, request);
66        
67        XmlObject[] paths = getConfiguration().selectPath( "$this/path" );
68        if( paths.length == 1 ) 
69        	path = paths[0].newCursor().getTextValue();
70        
71        paths = getConfiguration().selectPath( "$this/content" );
72        if( paths.length == 1 ) 
73        	content = paths[0].newCursor().getTextValue();
74     }
75     
76     public String getContent()
77  	{
78  		return content;
79  	}
80  
81  	public void setContent(String content)
82  	{
83  		this.content = content;
84  	}
85  
86  	public String getPath()
87  	{
88  		return path;
89  	}
90  
91  	public void setPath(String path)
92  	{
93  		this.path = path;
94  	}
95  
96  	public String assertRequest(WsdlTestRequest request) throws AssertionException
97     {
98  		return assertResponse( request.getResponseContent() );
99     }
100 	
101 	public String assertResponse( String response ) throws AssertionException
102 	{
103       try
104 		{
105       	if( path == null ) return "Missing path for XPath assertion";
106       	if( content == null ) return "Missing content for XPath assertion";
107       	
108       	XmlObject xml = XmlObject.Factory.parse( response );
109       	XmlObject[] items = xml.selectPath( path );
110       	
111       	XmlObject contentObj = null;
112       	
113       	try
114 			{
115 				contentObj = XmlObject.Factory.parse(content);
116 			}
117 			catch (Exception e)
118 			{
119 			}
120       	
121       	if( items.length == 0 )
122       		throw new Exception( "Missing content for xpath [" + path + "]" );
123       	
124       	XmlOptions options = new XmlOptions();
125    		options.setSavePrettyPrint();
126    		options.setSaveOuter();
127    		
128       	for( int c = 0; c < items.length; c++ )
129       	{
130       		try
131 				{
132 					if (contentObj == null)
133 					{
134 						if( items[c] instanceof XmlAnySimpleType )
135 						{
136 							XMLAssert.assertEquals(content, ((XmlAnySimpleType)items[c]).getStringValue() );
137 						}
138 						else
139 						{
140 							Node domNode = items[c].getDomNode();
141 							if (domNode.getNodeType() == Node.ELEMENT_NODE)
142 							{
143 								XMLAssert.assertEquals(content, XmlUtils.getElementText((Element) domNode));
144 							}
145 							else
146 							{
147 								XMLAssert.assertEquals(content, domNode.getNodeValue());
148 							}
149 						}
150 					}
151 					else
152 					{
153 						XMLAssert.assertXMLEqual(contentObj.xmlText(options), items[c].xmlText(options));
154 					}
155 					
156 					break;
157 				}
158 				catch (Throwable e)
159 				{
160 					if( c == items.length-1 )
161 						throw e;
162 				}
163       	}
164 		}
165 		catch (Throwable e)
166 		{
167 			String msg = "XPathContains assertion failed for path [" + path + 
168 					"] : " + e.getClass().getSimpleName() + ":" + e.getMessage();
169 			
170 			throw new AssertionException( new AssertionError(msg) );
171 		}
172       
173       return "Response matches content for [" + path + "]";
174    }
175 
176    public void configure()
177    {
178    	if( configurationDialog == null )
179    		buildConfigurationDialog();
180    	
181    	pathArea.setText( path );
182    	contentArea.setText( content );
183    	
184    	SoapUI.centerDialog( configurationDialog );
185    	configurationDialog.setVisible( true );
186    }
187 
188    private void buildConfigurationDialog()
189 	{
190       configurationDialog = new JDialog( SoapUI.getInstance().getFrame() );
191 		configurationDialog.setTitle("XPath Match configuration" );
192       
193       JPanel contentPanel = new JPanel( new BorderLayout() );
194       JLabel label = new JLabel( "<html><b>Specify xpath expression and matching content below</b><br>" +
195       		"declare namespaces with <code>declare namespace &lt;prefix&gt;='&lt;namespace&gt;';</code></html>" );
196       label.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
197       contentPanel.add( label, BorderLayout.NORTH );
198       
199       JSplitPane splitPane = UISupport.createVerticalSplit();
200       pathArea = new JTextArea();
201 		splitPane.setTopComponent( new JScrollPane( pathArea ));
202       
203       contentArea = new JTextArea();
204 		splitPane.setBottomComponent( new JScrollPane( contentArea ));
205 		splitPane.setDividerLocation( 100 );
206       splitPane.setBorder(BorderFactory.createEmptyBorder( 0, 3, 0, 3 ));
207 		
208       contentPanel.add( splitPane, BorderLayout.CENTER );
209       
210       ButtonBarBuilder builder = new ButtonBarBuilder();
211       
212       builder.addFixed( new JButton( new SelectFromCurrentAction() ));
213       builder.addRelatedGap();
214       builder.addFixed( new JButton( new TestPathAction() ));
215       builder.addRelatedGap();
216       builder.addFixed( new JButton( new DeclareNamespacesFromCurrentAction()));
217       
218       builder.addGlue();
219       builder.addFixed( new JButton( new OkAction() ));
220       builder.addRelatedGap();
221       builder.addFixed( new JButton( new CancelAction() ));
222       builder.setBorder( BorderFactory.createEmptyBorder( 3, 3, 3, 3 ));
223       
224       contentPanel.add( builder.getPanel(), BorderLayout.SOUTH );
225       
226       configurationDialog.setContentPane( contentPanel );
227       configurationDialog.setSize(500, 400);
228       
229       configurationDialog.setModal( false );
230 	}
231 
232 	public XmlObject createConfiguration()
233    {
234       XmlObject config = XmlObject.Factory.newInstance();
235       XmlCursor cursor = config.newCursor();
236       cursor.toNextToken();
237       cursor.insertElementWithText( "path", path );
238       cursor.insertElementWithText( "content", content );
239       cursor.dispose();
240       return config;
241    }
242 
243    public boolean isConfigurable()
244    {
245       return true;
246    }
247    
248    public class OkAction extends AbstractAction
249 	{
250 		public OkAction()
251 		{
252 			super( "Save" );
253 		}
254 
255 		public void actionPerformed(ActionEvent arg0)
256 		{
257 			setPath( pathArea.getText().trim() );
258 			setContent( contentArea.getText().trim() );
259 			setConfiguration( createConfiguration() );
260 			
261 			configurationDialog.setVisible( false );
262 		}
263 	}
264 
265    public class CancelAction extends AbstractAction
266    {
267    	public CancelAction()
268    	{
269    		super( "Cancel" );
270    	}
271    	
272 		public void actionPerformed(ActionEvent arg0)
273 		{
274 			configurationDialog.setVisible( false );
275 		}
276    }
277    
278    public class DeclareNamespacesFromCurrentAction extends AbstractAction
279    {
280    	public DeclareNamespacesFromCurrentAction()
281    	{
282    		super( "Declare" );
283    		putValue( Action.SHORT_DESCRIPTION, "Add namespace declaration from current response to xpath expression");
284    	}
285    	
286 		public void actionPerformed(ActionEvent arg0)
287 		{
288 			try
289 			{
290 				String responseContent = ((WsdlTestRequest) getRequest()).getResponseContent();
291 				if( responseContent == null || responseContent.trim().length() == 0 )
292 					return;
293 				
294 				pathArea.setText( XmlUtils.declareXPathNamespaces(responseContent ) + pathArea.getText() );
295 			}
296 			catch (Exception e)
297 			{
298 				log.error( e.getMessage() );
299 			}
300 	
301 		}
302    }
303    
304    public class TestPathAction extends AbstractAction
305 	{
306    	public TestPathAction()
307    	{
308    		super( "Test" );
309    	}
310    	
311 		public void actionPerformed(ActionEvent arg0)
312 		{
313 			String oldPath = getPath();
314 			String oldContent = getContent();
315 			
316 			setPath( pathArea.getText().trim() );
317 			setContent( contentArea.getText().trim() );
318 			
319 			try
320 			{
321 				String msg = assertRequest( ((WsdlTestRequest) getRequest()) );
322 				JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(), 
323 						 msg, "Success", JOptionPane.INFORMATION_MESSAGE );
324 			}
325 			catch (AssertionException e)
326 			{
327 				JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(), 
328 						 e.getMessage(), "Assertion Failed", JOptionPane.ERROR_MESSAGE );
329 			}
330 
331 			setPath( oldPath );
332 			setContent( oldContent );
333 		}
334 	}
335    
336    public class SelectFromCurrentAction extends AbstractAction
337 	{
338       private XmlOptions options;
339 
340 		public SelectFromCurrentAction()
341       {
342       	super( "Select from current" );
343       	
344       	options = new XmlOptions();
345 			options.setSavePrettyPrint();
346    		options.setSaveOuter();
347    		options.setSaveAggressiveNamespaces();
348       }
349    	
350 		public void actionPerformed(ActionEvent arg0)
351 		{
352 			try
353 			{
354 				XmlObject xml = XmlObject.Factory
355 						.parse(((WsdlTestRequest) getRequest()).getResponseContent());
356 				
357 				String txt = pathArea.getSelectedText();
358 				if( txt == null ) txt = pathArea.getText();
359 				
360 				XmlObject[] items = xml.selectPath(txt.trim()); 
361 				
362 				contentArea.setText("");
363 				
364 				if( items.length == 0 )
365 				{
366 					JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(), 
367 							"No match in current response", "Error", JOptionPane.ERROR_MESSAGE );
368 				}
369 				else if( items.length > 1 )
370 				{
371 					JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(), 
372 							"More than one match in current response", "Error", JOptionPane.ERROR_MESSAGE );
373 				}
374 				else
375 				{
376 					if( items[0] instanceof XmlAnySimpleType )
377 					{
378 						contentArea.setText( ((XmlAnySimpleType)items[0]).getStringValue() );
379 					}
380 					else
381 					{
382 						Node domNode = items[0].getDomNode();
383 						if (domNode.getNodeType() == Node.ELEMENT_NODE)
384 						{
385 							contentArea.setText( items[0].xmlText(options));
386 						}
387 						else
388 						{
389 							contentArea.setText( domNode.getNodeValue());
390 						}
391 					}
392 				}
393 			}
394 			catch (Throwable e)
395 			{
396 				JOptionPane.showMessageDialog( SoapUI.getInstance().getFrame(), 
397 						 e.getMessage(), "Error", JOptionPane.OK_OPTION );
398 			}			
399 		}
400 
401 	}
402 }