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.util.HashMap;
16  import java.util.Map;
17  
18  import org.apache.xmlbeans.XmlObject;
19  
20  import com.eviware.soapui.config.TestAssertionConfig;
21  import com.eviware.soapui.impl.rest.RestResource;
22  import com.eviware.soapui.impl.rest.RestService;
23  import com.eviware.soapui.impl.support.AbstractInterface;
24  import com.eviware.soapui.impl.support.DefinitionContext;
25  import com.eviware.soapui.impl.wadl.WadlDefinitionContext;
26  import com.eviware.soapui.impl.wadl.support.WadlValidator;
27  import com.eviware.soapui.impl.wsdl.WsdlInterface;
28  import com.eviware.soapui.impl.wsdl.WsdlOperation;
29  import com.eviware.soapui.impl.wsdl.submit.RestMessageExchange;
30  import com.eviware.soapui.impl.wsdl.submit.WsdlMessageExchange;
31  import com.eviware.soapui.impl.wsdl.support.PathUtils;
32  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
33  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext;
34  import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator;
35  import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion;
36  import com.eviware.soapui.impl.wsdl.teststeps.assertions.AbstractTestAssertionFactory;
37  import com.eviware.soapui.model.iface.MessageExchange;
38  import com.eviware.soapui.model.iface.SubmitContext;
39  import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext;
40  import com.eviware.soapui.model.testsuite.Assertable;
41  import com.eviware.soapui.model.testsuite.AssertionError;
42  import com.eviware.soapui.model.testsuite.AssertionException;
43  import com.eviware.soapui.model.testsuite.RequestAssertion;
44  import com.eviware.soapui.model.testsuite.ResponseAssertion;
45  import com.eviware.soapui.model.testsuite.TestCaseRunContext;
46  import com.eviware.soapui.model.testsuite.TestCaseRunner;
47  import com.eviware.soapui.support.StringUtils;
48  import com.eviware.soapui.support.UISupport;
49  import com.eviware.soapui.support.xml.XmlObjectConfigurationBuilder;
50  import com.eviware.soapui.support.xml.XmlObjectConfigurationReader;
51  
52  /***
53   * Asserts that a request or response message complies with its related WSDL
54   * definition / XML Schema
55   * 
56   * @author Ole.Matzura
57   */
58  
59  public class SchemaComplianceAssertion extends WsdlMessageAssertion implements RequestAssertion, ResponseAssertion
60  {
61  	public static final String ID = "Schema Compliance";
62  	public static final String LABEL = "Schema Compliance";
63  
64  	private String definition;
65  	private DefinitionContext<?> definitionContext;
66  	private String wsdlContextDef;
67  	private static Map<String, WsdlContext> wsdlContextMap = new HashMap<String, WsdlContext>();
68  	private static final String SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG = SchemaComplianceAssertion.class.getName()
69  			+ "@SchemaComplianceHasClearedCacheFlag";
70  
71  	public SchemaComplianceAssertion( TestAssertionConfig assertionConfig, Assertable assertable )
72  	{
73  		super( assertionConfig, assertable, false, true, false, true );
74  
75  		XmlObjectConfigurationReader reader = new XmlObjectConfigurationReader( getConfiguration() );
76  		definition = reader.readString( "definition", null );
77  	}
78  
79  	@Override
80  	public void prepare( TestCaseRunner testRunner, TestCaseRunContext testRunContext ) throws Exception
81  	{
82  		super.prepare( testRunner, testRunContext );
83  
84  		definitionContext = null;
85  		wsdlContextDef = null;
86  
87  		// get correct context for checking if cache has been cleared for this run
88  		PropertyExpansionContext context = testRunContext.hasProperty( TestCaseRunContext.LOAD_TEST_CONTEXT ) ? ( PropertyExpansionContext )testRunContext
89  				.getProperty( TestCaseRunContext.LOAD_TEST_CONTEXT )
90  				: testRunContext;
91  
92  		synchronized( context )
93  		{
94  			if( !context.hasProperty( SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG ) )
95  			{
96  				wsdlContextMap.clear();
97  				context.setProperty( SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG, "yep!" );
98  			}
99  		}
100 	}
101 
102 	protected String internalAssertResponse( MessageExchange messageExchange, SubmitContext context )
103 			throws AssertionException
104 	{
105 		if( messageExchange instanceof WsdlMessageExchange )
106 		{
107 			return assertWsdlResponse( ( WsdlMessageExchange )messageExchange, context );
108 		}
109 		else if( messageExchange instanceof RestMessageExchange )
110 		{
111 			return assertWadlResponse( ( RestMessageExchange )messageExchange, context );
112 		}
113 
114 		throw new AssertionException( new AssertionError( "Unknown MessageExchange type" ) );
115 	}
116 
117 	private String assertWadlResponse( RestMessageExchange messageExchange, SubmitContext context )
118 			throws AssertionException
119 	{
120 		WadlDefinitionContext wadlContext = null;
121 		try
122 		{
123 			definitionContext = getWadlContext( messageExchange, context );
124 		}
125 		catch( Exception e1 )
126 		{
127 			throw new AssertionException( new AssertionError( e1.getMessage() ) );
128 		}
129 
130 		WadlValidator validator = new WadlValidator( wadlContext );
131 
132 		try
133 		{
134 			AssertionError[] errors = validator.assertResponse( messageExchange );
135 			if( errors.length > 0 )
136 				throw new AssertionException( errors );
137 		}
138 		catch( AssertionException e )
139 		{
140 			throw e;
141 		}
142 		catch( Exception e )
143 		{
144 			throw new AssertionException( new AssertionError( e.getMessage() ) );
145 		}
146 
147 		return "Schema compliance OK";
148 	}
149 
150 	private String assertWsdlResponse( WsdlMessageExchange messageExchange, SubmitContext context )
151 			throws AssertionException
152 	{
153 		WsdlContext wsdlContext = null;
154 		try
155 		{
156 			wsdlContext = ( WsdlContext )getWsdlContext( messageExchange, context );
157 		}
158 		catch( Exception e1 )
159 		{
160 			throw new AssertionException( new AssertionError( e1.getMessage() ) );
161 		}
162 
163 		WsdlValidator validator = new WsdlValidator( wsdlContext );
164 
165 		try
166 		{
167 			AssertionError[] errors = validator.assertResponse( messageExchange, false );
168 			if( errors.length > 0 )
169 				throw new AssertionException( errors );
170 		}
171 		catch( AssertionException e )
172 		{
173 			throw e;
174 		}
175 		catch( Exception e )
176 		{
177 			throw new AssertionException( new AssertionError( e.getMessage() ) );
178 		}
179 
180 		return "Schema compliance OK";
181 	}
182 
183 	private DefinitionContext<?> getWsdlContext( WsdlMessageExchange messageExchange, SubmitContext context )
184 			throws Exception
185 	{
186 		WsdlOperation operation = messageExchange.getOperation();
187 		WsdlInterface iface = operation.getInterface();
188 		String def = PathUtils.expandPath( definition, iface, context );
189 		if( StringUtils.isNullOrEmpty( def ) || def.equals( iface.getDefinition() ) )
190 		{
191 			definitionContext = ( iface ).getWsdlContext();
192 			( ( WsdlContext )definitionContext ).loadIfNecessary();
193 		}
194 		else
195 		{
196 			if( definitionContext == null || !def.equals( wsdlContextDef ) )
197 			{
198 				definitionContext = getContext( def, iface.getSoapVersion() );
199 				// ( (WsdlContext) definitionContext ).load();
200 				( ( WsdlContext )definitionContext ).setInterface( iface );
201 				wsdlContextDef = def;
202 			}
203 		}
204 
205 		return definitionContext;
206 	}
207 
208 	private synchronized WsdlContext getContext( String wsdlLocation, SoapVersion soapVersion ) throws Exception
209 	{
210 		if( wsdlContextMap.containsKey( wsdlLocation ) )
211 		{
212 			return wsdlContextMap.get( wsdlLocation );
213 		}
214 		else
215 		{
216 			WsdlContext newWsdlContext = new WsdlContext( wsdlLocation, soapVersion );
217 			newWsdlContext.load();
218 			wsdlContextMap.put( wsdlLocation, newWsdlContext );
219 			return newWsdlContext;
220 		}
221 	}
222 
223 	private DefinitionContext<?> getWadlContext( RestMessageExchange messageExchange, SubmitContext context )
224 			throws Exception
225 	{
226 		RestResource operation = messageExchange.getResource();
227 		RestService service = operation.getService();
228 		if( StringUtils.isNullOrEmpty( definition )
229 				|| definition.equals( PathUtils.expandPath( service.getDefinition(), service, context ) ) )
230 		{
231 			definitionContext = service.getWadlContext();
232 			( ( WadlDefinitionContext )definitionContext ).loadIfNecessary();
233 		}
234 		else
235 		{
236 			String def = PathUtils.expandPath( definition, service, context );
237 			if( definitionContext == null || !def.equals( wsdlContextDef ) )
238 			{
239 				definitionContext = new WadlDefinitionContext( def );
240 				( ( WadlDefinitionContext )definitionContext ).load();
241 				( ( WadlDefinitionContext )definitionContext ).setInterface( service );
242 				wsdlContextDef = def;
243 			}
244 		}
245 
246 		return definitionContext;
247 	}
248 
249 	public boolean configure()
250 	{
251 		String value = definition;
252 
253 		AbstractInterface<?> iface = ( AbstractInterface<?> )getAssertable().getInterface();
254 		String orgDef = iface == null ? null : iface.getDefinition();
255 
256 		if( StringUtils.isNullOrEmpty( value ) )
257 		{
258 			value = orgDef;
259 		}
260 
261 		value = UISupport.prompt( "Specify definition url to validate by", "Configure SchemaCompliance Assertion", value );
262 
263 		if( value == null )
264 			return false;
265 
266 		if( StringUtils.isNullOrEmpty( value ) || value.equals( orgDef ) )
267 			definition = "";
268 		else
269 			definition = value;
270 
271 		setConfiguration( createConfiguration() );
272 		return true;
273 	}
274 
275 	protected XmlObject createConfiguration()
276 	{
277 		XmlObjectConfigurationBuilder builder = new XmlObjectConfigurationBuilder();
278 		return builder.add( "definition", definition ).finish();
279 	}
280 
281 	protected String internalAssertRequest( MessageExchange messageExchange, SubmitContext context )
282 			throws AssertionException
283 	{
284 		WsdlContext wsdlContext = null;
285 		try
286 		{
287 			wsdlContext = ( WsdlContext )getWsdlContext( ( WsdlMessageExchange )messageExchange, context );
288 		}
289 		catch( Exception e1 )
290 		{
291 			throw new AssertionException( new AssertionError( e1.getMessage() ) );
292 		}
293 		WsdlValidator validator = new WsdlValidator( wsdlContext );
294 
295 		try
296 		{
297 			AssertionError[] errors = validator.assertRequest( ( WsdlMessageExchange )messageExchange, false );
298 			if( errors.length > 0 )
299 				throw new AssertionException( errors );
300 		}
301 		catch( AssertionException e )
302 		{
303 			throw e;
304 		}
305 		catch( Exception e )
306 		{
307 			throw new AssertionException( new AssertionError( e.getMessage() ) );
308 		}
309 
310 		return "Schema compliance OK";
311 	}
312 
313 	public static class Factory extends AbstractTestAssertionFactory
314 	{
315 		public Factory()
316 		{
317 			super( SchemaComplianceAssertion.ID, SchemaComplianceAssertion.LABEL, SchemaComplianceAssertion.class );
318 		}
319 
320 		@Override
321 		public boolean canAssert( Assertable assertable )
322 		{
323 			return super.canAssert( assertable ) && assertable.getInterface() instanceof AbstractInterface
324 					&& ( ( AbstractInterface<?> )assertable.getInterface() ).getDefinitionContext().hasSchemaTypes();
325 		}
326 	}
327 }