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.mockaswar;
14  
15  import java.io.File;
16  import java.io.FileInputStream;
17  import java.io.IOException;
18  import java.io.PrintWriter;
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.logging.Level;
22  import java.util.logging.Logger;
23  
24  import javax.servlet.ServletContext;
25  import javax.servlet.ServletException;
26  import javax.servlet.http.HttpServlet;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  
30  import org.apache.commons.collections.list.TreeList;
31  import org.apache.log4j.spi.LoggingEvent;
32  
33  import com.eviware.soapui.DefaultSoapUICore;
34  import com.eviware.soapui.SoapUI;
35  import com.eviware.soapui.impl.wsdl.WsdlProject;
36  import com.eviware.soapui.impl.wsdl.mock.DispatchException;
37  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
38  import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
39  import com.eviware.soapui.model.mock.MockResult;
40  import com.eviware.soapui.model.mock.MockRunner;
41  import com.eviware.soapui.model.mock.MockService;
42  import com.eviware.soapui.monitor.MockEngine;
43  import com.eviware.soapui.support.StringUtils;
44  import com.eviware.soapui.support.Tools;
45  import com.eviware.soapui.support.editor.inspectors.attachments.ContentTypeHandler;
46  import com.eviware.soapui.support.types.StringToStringsMap;
47  import com.eviware.soapui.support.xml.XmlUtils;
48  
49  /***
50   * Servlet implementation class SoapUIMockServlet
51   */
52  @SuppressWarnings( "unchecked" )
53  public class MockAsWarServlet extends HttpServlet
54  {
55  
56  	private static final long serialVersionUID = 1L;
57  	protected static Logger logger = Logger.getLogger( MockAsWarServlet.class.getName() );
58  	private WsdlProject project;
59  	private long maxResults;
60  	private List<MockResult> results = new TreeList();
61  	private List<LoggingEvent> events = new TreeList();
62  	private boolean enableWebUI;
63  
64  	public void init() throws ServletException
65  	{
66  		super.init();
67  		try
68  		{
69  			String mockServiceEndpoint = initMockServiceParameters();
70  
71  			logger.info( "Loading project" );
72  			project = new WsdlProject( getServletContext().getRealPath( getInitParameter( "projectFile" ) ) );
73  
74  			logger.info( "Starting MockService(s)" );
75  
76  			for( MockService mockService : project.getMockServiceList() )
77  			{
78  				logger.info( "Starting mockService [" + mockService.getName() + "]" );
79  				if( StringUtils.hasContent( mockServiceEndpoint ) )
80  				{
81  					( ( WsdlMockService )mockService ).setMockServiceEndpoint( mockServiceEndpoint );
82  				}
83  
84  				mockService.start();
85  			}
86  		}
87  		catch( Exception ex )
88  		{
89  			logger.log( Level.SEVERE, null, ex );
90  		}
91  	}
92  
93  	protected String initMockServiceParameters()
94  	{
95  		if( StringUtils.hasContent( getInitParameter( "listeners" ) ) )
96  		{
97  			logger.info( "Init listeners" );
98  			System.setProperty( "soapui.ext.listeners", getServletContext().getRealPath( getInitParameter( "listeners" ) ) );
99  		}
100 		else
101 		{
102 			logger.info( "Listeners not set!" );
103 		}
104 
105 		if( StringUtils.hasContent( getInitParameter( "actions" ) ) )
106 		{
107 			logger.info( "Init actions" );
108 			System.setProperty( "soapui.ext.actions", getServletContext().getRealPath( getInitParameter( "actions" ) ) );
109 		}
110 		else
111 		{
112 			logger.info( "Actions not set!" );
113 		}
114 
115 		if( StringUtils.hasContent( getInitParameter( "soapuiSettings" ) ) )
116 		{
117 			logger.info( "Init settings" );
118 			SoapUI.setSoapUICore( new MockServletSoapUICore( getServletContext(), getInitParameter( "soapuiSettings" ) ),
119 					true );
120 		}
121 		else
122 		{
123 			logger.info( "Settings not set!" );
124 			SoapUI.setSoapUICore( new MockServletSoapUICore( getServletContext() ), true );
125 		}
126 
127 		if( StringUtils.hasContent( getInitParameter( "enableWebUI" ) ) )
128 		{
129 			if( "true".equals( getInitParameter( "enableWebUI" ) ) )
130 			{
131 				logger.info( "WebUI ENABLED" );
132 				enableWebUI = true;
133 			}
134 			else
135 			{
136 				logger.info( "WebUI DISABLED" );
137 				enableWebUI = false;
138 			}
139 		}
140 
141 		try
142 		{
143 			maxResults = Integer.parseInt( getInitParameter( "maxResults" ) );
144 		}
145 		catch( Throwable t )
146 		{
147 			maxResults = 1000;
148 		}
149 
150 		SoapUI.ensureGroovyLog().addAppender( new GroovyLogAppender() );
151 
152 		String mockServiceEndpoint = getInitParameter( "mockServiceEndpoint" );
153 		return mockServiceEndpoint;
154 	}
155 
156 	public void destroy()
157 	{
158 		super.destroy();
159 		getMockServletCore().stop();
160 	}
161 
162 	protected MockServletSoapUICore getMockServletCore()
163 	{
164 		return ( MockServletSoapUICore )SoapUI.getSoapUICore();
165 	}
166 
167 	protected void service( HttpServletRequest request, HttpServletResponse response ) throws ServletException,
168 			IOException
169 	{
170 		try
171 		{
172 			getMockServletCore().dispatchRequest( request, response );
173 		}
174 		catch( DispatchException ex )
175 		{
176 			logger.log( Level.SEVERE, null, ex );
177 		}
178 	}
179 
180 	private void printResult( PrintWriter out, MockResult result )
181 	{
182 
183 		out.print( "<h4>Details for MockResult at " + new java.util.Date( result.getTimestamp() ) + " ("
184 				+ result.getTimeTaken() + "ms)</h4>" );
185 
186 		out.println( "<hr/><p><b>Request Headers</b>:</p>" );
187 		out.print( "<table border=\"1\"><tr><td>Header</td><td>Value</td></tr>" );
188 		StringToStringsMap headers = result.getMockRequest().getRequestHeaders();
189 		for( String name : headers.getKeys() )
190 		{
191 			for( String value : headers.get( name ) )
192 				out.println( "<tr><td>" + name + "</td><td>" + value + "</td></tr>" );
193 		}
194 		out.println( "</table>" );
195 
196 		out.println( "<hr/><b>Incoming Request</b>:<br/><pre>"
197 				+ XmlUtils.entitize( result.getMockRequest().getRequestContent() ) + "</pre>" );
198 
199 		out.println( "<hr/><p><b>Response Headers</b>:</p>" );
200 		out.print( "<table border\"1\"><tr><td>Header</td><td>Value</td></tr>" );
201 		headers = result.getResponseHeaders();
202 		for( String name : headers.getKeys() )
203 		{
204 			for( String value : headers.get( name ) )
205 				out.println( "<tr><td>" + name + "</td><td>" + value + "</td></tr>" );
206 		}
207 		out.println( "</table>" );
208 
209 		out.println( "<hr/><b>Returned Response</b>:<pre>" + XmlUtils.entitize( result.getResponseContent() ) + "</pre>" );
210 	}
211 
212 	private List<MockRunner> mockRunners = new ArrayList<MockRunner>();
213 
214 	class MockServletSoapUICore extends DefaultSoapUICore implements MockEngine
215 	{
216 		private final ServletContext servletContext;
217 
218 		public MockServletSoapUICore( ServletContext servletContext, String soapUISettings )
219 		{
220 			super( servletContext.getRealPath( "/" ), servletContext.getRealPath( soapUISettings ) );
221 			this.servletContext = servletContext;
222 		}
223 
224 		public void dispatchRequest( HttpServletRequest request, HttpServletResponse response ) throws DispatchException,
225 				IOException
226 		{
227 			String pathInfo = request.getPathInfo();
228 			if( pathInfo == null )
229 				pathInfo = "";
230 
231 			for( MockRunner mockRunner : getMockRunners() )
232 			{
233 				if( pathInfo.equals( mockRunner.getMockService().getPath() ) )
234 				{
235 					MockResult result = mockRunner.dispatchRequest( request, response );
236 
237 					if( maxResults > 0 )
238 					{
239 						synchronized( results )
240 						{
241 							while( maxResults > 0 && results.size() > maxResults )
242 							{
243 								results.remove( 0 );
244 							}
245 							if( result != null )
246 							{
247 								results.add( result );
248 							}
249 						}
250 					}
251 					return;
252 				}
253 			}
254 
255 			if( enableWebUI )
256 			{
257 				String realPath = servletContext.getRealPath( pathInfo );
258 				File file = realPath == null ? null : new File( realPath );
259 				if( file != null && file.exists() && file.isFile() )
260 				{
261 					FileInputStream in = new FileInputStream( file );
262 					response.setStatus( HttpServletResponse.SC_OK );
263 					long length = file.length();
264 					response.setContentLength( ( int )length );
265 					response.setContentType( ContentTypeHandler.getContentTypeFromFilename( file.getName() ) );
266 					Tools.readAndWrite( in, length, response.getOutputStream() );
267 					in.close();
268 				}
269 				else if( pathInfo.equals( "/master" ) )
270 				{
271 					printMaster( request, response );
272 				}
273 				else if( pathInfo.equals( "/detail" ) )
274 				{
275 					printDetail( request, response );
276 				}
277 				else if( pathInfo.equals( "/log" ) )
278 				{
279 					printLog( request, response );
280 				}
281 				else
282 				{
283 					printFrameset( request, response );
284 				}
285 			}
286 			else
287 			{
288 				printDisabledLogFrameset( request, response );
289 			}
290 		}
291 
292 		public void stop()
293 		{
294 			for( MockRunner mockRunner : getMockRunners() )
295 			{
296 				mockRunner.stop();
297 			}
298 		}
299 
300 		public MockServletSoapUICore( ServletContext servletContext )
301 		{
302 			super( servletContext.getRealPath( "/" ), null );
303 			this.servletContext = servletContext;
304 		}
305 
306 		@Override
307 		protected MockEngine buildMockEngine()
308 		{
309 			return this;
310 		}
311 
312 		public MockRunner[] getMockRunners()
313 		{
314 			return mockRunners.toArray( new MockRunner[mockRunners.size()] );
315 		}
316 
317 		public boolean hasRunningMock( MockService mockService )
318 		{
319 			for( MockRunner runner : mockRunners )
320 			{
321 				if( runner.getMockService() == mockService )
322 				{
323 					return true;
324 				}
325 			}
326 
327 			return false;
328 		}
329 
330 		public void startMockService( MockRunner runner ) throws Exception
331 		{
332 			mockRunners.add( runner );
333 		}
334 
335 		public void stopMockService( MockRunner runner )
336 		{
337 			mockRunners.remove( runner );
338 		}
339 	}
340 
341 	public void printMaster( HttpServletRequest request, HttpServletResponse response ) throws IOException
342 	{
343 		response.setStatus( HttpServletResponse.SC_OK );
344 		response.setContentType( "text/html" );
345 
346 		PrintWriter out = response.getWriter();
347 		startHtmlPage( out, "MockService Log Table", "15" );
348 
349 		out.print( "<h3><img src=\"header_logo.jpg\"> soapUI MockServices Log for project [" + project.getName()
350 				+ "]</h3>" + "<p style=\"text-align: left\">WSDLs:" );
351 		for( MockRunner mockRunner : mockRunners )
352 		{
353 			String overviewUrl = ( ( WsdlMockRunner )mockRunner ).getOverviewUrl();
354 			if( overviewUrl.startsWith( "/" ) )
355 			{
356 				overviewUrl = overviewUrl.substring( 1 );
357 			}
358 
359 			out.print( " [<a target=\"new\" href=\"" + overviewUrl + "\">" + mockRunner.getMockService().getName()
360 					+ "</a>]" );
361 		}
362 
363 		out.print( "</p>" );
364 
365 		out.print( "<hr/><p><b>Processed Requests</b>: " );
366 		out.print( "[<a href=\"master\">Refresh</a>] " );
367 		out.print( "[<a href=\"master?clear\">Clear</a>]</p>" );
368 
369 		if( "clear".equals( request.getQueryString() ) )
370 		{
371 			results.clear();
372 		}
373 
374 		out.print( "<table border=\"1\">" );
375 		out.print( "<tr><td></td><td>Timestamp</td><td>Time Taken</td><td>MockOperation</td><td>MockResponse</td><td>MockService</td></tr>" );
376 
377 		int cnt = 1;
378 
379 		for( MockResult result : results )
380 		{
381 
382 			out.print( "<tr><td>" + ( cnt++ ) + "</td>" );
383 			out.print( "<td><a target=\"detail\" href=\"detail?" + result.hashCode() + "\">"
384 					+ new java.util.Date( result.getTimestamp() ) + "</a></td>" );
385 			out.print( "<td>" + result.getTimeTaken() + "</td>" );
386 			out.print( "<td>" + result.getMockOperation().getName() + "</td>" );
387 			out.print( "<td>" + result.getMockResponse().getName() + "</td>" );
388 			out.print( "<td>" + result.getMockOperation().getMockService().getName() + "</td></tr>" );
389 		}
390 
391 		out.print( "</table>" );
392 
393 		out.print( "</body></html>" );
394 		out.flush();
395 
396 	}
397 
398 	private void startHtmlPage( PrintWriter out, String title, String refresh )
399 	{
400 		out.print( "<html><head>" );
401 		out.print( "<title>" + title + "</title>" );
402 		if( refresh != null )
403 		{
404 			out.print( "<meta http-equiv=\"refresh\" content=\"" + refresh + "\"/>" );
405 		}
406 
407 		out.print( "<link type=\"text/css\" rel=\"stylesheet\" href=\"stylesheet.css\"/>" );
408 		out.print( "</head><body>" );
409 	}
410 
411 	public void printDisabledLogFrameset( HttpServletRequest request, HttpServletResponse response ) throws IOException
412 	{
413 		response.setStatus( HttpServletResponse.SC_OK );
414 		response.setContentType( "text/html" );
415 
416 		PrintWriter out = response.getWriter();
417 		out.print( "<html><head><title>soapUI MockServices Log for project [" + project.getName() + "]</title></head>" );
418 		out.print( "<body>" );
419 		out.print( "<h3>" );
420 		out.print( "Log is disabled." );
421 		out.print( "</h3>" );
422 		out.print( "</body></html>" );
423 		out.flush();
424 	}
425 
426 	public void printFrameset( HttpServletRequest request, HttpServletResponse response ) throws IOException
427 	{
428 		response.setStatus( HttpServletResponse.SC_OK );
429 		response.setContentType( "text/html" );
430 
431 		PrintWriter out = response.getWriter();
432 		out.print( "<html><head><title>soapUI MockServices Log for project [" + project.getName() + "]</title></head>" );
433 		out.print( "<frameset rows=\"40%,40%,*\">" );
434 		out.print( "<frame src=\"master\"/>" );
435 		out.print( "<frame name=\"detail\" src=\"detail\"/>" );
436 		out.print( "<frame src=\"log\"/>" );
437 		out.print( "</frameset>" );
438 		out.print( "</html>" );
439 		out.flush();
440 	}
441 
442 	public void printDetail( HttpServletRequest request, HttpServletResponse response ) throws IOException
443 	{
444 		response.setStatus( HttpServletResponse.SC_OK );
445 		response.setContentType( "text/html" );
446 
447 		PrintWriter out = response.getWriter();
448 
449 		startHtmlPage( out, "MockService Detail", null );
450 
451 		int id = 0;
452 
453 		try
454 		{
455 			id = Integer.parseInt( request.getQueryString() );
456 		}
457 		catch( NumberFormatException e )
458 		{
459 		}
460 
461 		if( id > 0 )
462 		{
463 			for( MockResult result : results )
464 			{
465 				if( result.hashCode() == id )
466 				{
467 					id = 0;
468 					printResult( out, result );
469 				}
470 			}
471 		}
472 
473 		if( id > 0 )
474 		{
475 			out.print( "<p>Missing specified MockResult</p>" );
476 		}
477 
478 		out.print( "</body></html>" );
479 		out.flush();
480 	}
481 
482 	private class GroovyLogAppender extends org.apache.log4j.AppenderSkeleton
483 	{
484 
485 		protected void append( LoggingEvent event )
486 		{
487 			events.add( event );
488 		}
489 
490 		public void close()
491 		{
492 		}
493 
494 		public boolean requiresLayout()
495 		{
496 			return false;
497 		}
498 	}
499 
500 	public void printLog( HttpServletRequest request, HttpServletResponse response ) throws IOException
501 	{
502 		response.setStatus( HttpServletResponse.SC_OK );
503 		response.setContentType( "text/html" );
504 
505 		PrintWriter out = response.getWriter();
506 		startHtmlPage( out, "MockService Groovy Log", "15" );
507 		out.print( "<p><b>Groovy Log output</b>: " );
508 		out.print( "[<a href=\"log\">Refresh</a>] " );
509 		out.print( "[<a href=\"log?clear\">Clear</a>]</p>" );
510 
511 		if( "clear".equals( request.getQueryString() ) )
512 		{
513 			events.clear();
514 		}
515 
516 		out.print( "<table border=\"1\">" );
517 		out.print( "<tr><td></td><td>Timestamp</td><td>Message</td></tr>" );
518 
519 		int cnt = 1;
520 
521 		for( LoggingEvent event : events )
522 		{
523 
524 			out.print( "<tr><td>" + ( cnt++ ) + "</td>" );
525 			out.print( "<td>" + new java.util.Date( event.timeStamp ) + "</td>" );
526 			out.print( "<td>" + event.getRenderedMessage() + "</td></tr>" );
527 		}
528 
529 		out.print( "</table>" );
530 
531 		out.print( "</body></html>" );
532 		out.flush();
533 	}
534 }