View Javadoc

    1   /*
    2    *  soapUI, copyright (C) 2004-2007 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.monitor;
    14
    15  import java.io.IOException;
    16  import java.util.ArrayList;
    17  import java.util.HashMap;
    18  import java.util.HashSet;
    19  import java.util.List;
    20  import java.util.Map;
    21  import java.util.Set;
    22
    23  import javax.servlet.ServletException;
    24  import javax.servlet.http.HttpServletRequest;
    25  import javax.servlet.http.HttpServletResponse;
    26
    27  import org.apache.log4j.Logger;
    28  import org.mortbay.jetty.HttpConnection;
    29  import org.mortbay.jetty.Server;
    30  import org.mortbay.jetty.handler.AbstractHandler;
    31  import org.mortbay.jetty.nio.SelectChannelConnector;
    32  import org.mortbay.thread.BoundedThreadPool;
    33
    34  import com.eviware.soapui.SoapUI;
    35  import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
    36  import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
    37  import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
    38  import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
    39  import com.eviware.soapui.model.mock.MockRunner;
    40  import com.eviware.soapui.model.mock.MockService;
    41  import com.eviware.soapui.support.UISupport;
    42  import com.eviware.soapui.support.log.JettyLogger;
    43
    44  /***
    45   * Core Mock-Engine hosting a Jetty web server
    46   *
    47   * @author ole.matzura
    48   */
    49
    50  public class MockEngine
    51  {
    52  	private final static Logger log = Logger.getLogger( MockEngine.class );
    53
    54  	private Server server;
    55  	private Map<Integer, Map<String,MockRunner> > runners = new HashMap<Integer, Map<String,MockRunner> >();
    56  	private Map<Integer, SoapUIConnector> connectors = new HashMap<Integer,SoapUIConnector>();
    57  	private List<MockRunner> mockRunners = new ArrayList<MockRunner>();
    58
    59  	public MockEngine()
    60  	{
    61  		System.setProperty( "org.mortbay.log.class", JettyLogger.class.getName() );
    62  	}
    63
    64  	public boolean hasRunningMock( MockService mockService )
    65  	{
    66  		for( MockRunner runner : mockRunners )
    67  			if( runner.getMockService() == mockService )
    68  				return true;
    69
    70  		return false;
    71  	}
    72
    73  	public void startMockService( MockRunner runner ) throws Exception
    74  	{
    75  		if( server == null )
    76  			initServer();
    77
    78  		MockService mockService = runner.getMockService();
    79  		int port = mockService.getPort();
    80
    81  		if( !runners.containsKey( port ))
    82  		{
    83  			SoapUIConnector connector = new SoapUIConnector();
    84
    85  			connector.setPort( port );
    86  			boolean wasRunning = server.isRunning();
    87
    88  			if( wasRunning )
    89  			{
    90  				server.stop();
    91  			}
    92
    93  			server.addConnector( connector );
    94  			try
    95  			{
    96  				server.start();
    97  			}
    98  			catch( RuntimeException e )
    99  			{
    100 				UISupport.showErrorMessage( e );
    101
    102 				server.removeConnector( connector );
    103 				if( wasRunning )
    104 				{
    105 					server.start();
    106 					return;
    107 				}
    108 			}
    109
    110 			connectors.put( new Integer( port), connector );
    111 			runners.put( new Integer( port), new HashMap<String,MockRunner>() );
    112 		}
    113
    114 		Map<String, MockRunner> map = runners.get( port );
    115 		String path = mockService.getPath();
    116 		map.put( path, runner );
    117 		mockRunners.add( runner );
    118
    119 		log.info(  "Started mockService [" + mockService.getName() + "] on port [" + port + "] at path [" + path + "]" );
    120 	}
    121
    122 	private void initServer() throws Exception
    123 	{
    124 		server = new Server();
    125 		BoundedThreadPool threadPool = new BoundedThreadPool();
    126 		threadPool.setMaxThreads( 100 );
    127 		server.setThreadPool( threadPool );
    128
    129 		server.setHandler( new ServerHandler() );
    130 	}
    131
    132 	public void stopMockService( WsdlMockRunner runner )
    133 	{
    134 		MockService mockService = runner.getMockService();
    135 		final Integer port = new Integer( mockService.getPort());
    136 		Map<String, MockRunner> map = runners.get( port );
    137
    138 		map.remove( mockService.getPath() );
    139 		mockRunners.remove( runner );
    140
    141 		if( map.isEmpty() )
    142 		{
    143 			SoapUIConnector connector = ( SoapUIConnector ) connectors.get( port );
    144 			if( connector == null )
    145 			{
    146 				log.warn( "Missing connectors on port [" + port + "]" );
    147 				return;
    148 			}
    149
    150 			try
    151 			{
    152 				log.info( "Stopping connector on port " + port );
    153 				if( !connector.waitUntilIdle( 5000 ))
    154 				{
    155 					log.warn(  "Failed to wait for idle.. stopping connector anyway.." );
    156 				}
    157 				connector.stop();
    158 			}
    159 			catch( Exception e )
    160 			{
    161 				SoapUI.logError( e );
    162 			}
    163 			server.removeConnector( connector );
    164 			runners.remove( port );
    165 			if( runners.isEmpty() )
    166 			{
    167 				try
    168 				{
    169 					log.info( "No more connectors.. stopping server" );
    170 					server.stop();
    171 				}
    172 				catch( Exception e )
    173 				{
    174 					SoapUI.logError( e );
    175 				}
    176 			}
    177 		}
    178 	}
    179
    180 	private class SoapUIConnector extends SelectChannelConnector
    181 	{
    182 		private Set<HttpConnection> connections = new HashSet<HttpConnection>();
    183
    184 		@Override
    185 		protected void connectionClosed( HttpConnection arg0 )
    186 		{
    187 			super.connectionClosed( arg0 );
    188 			connections.remove( arg0 );
    189 		}
    190
    191 		@Override
    192 		protected void connectionOpened( HttpConnection arg0 )
    193 		{
    194 			super.connectionOpened( arg0 );
    195 			connections.add( arg0 );
    196 		}
    197
    198 		public boolean waitUntilIdle( long maxwait ) throws Exception
    199 		{
    200 			while( maxwait > 0 && hasActiveConnections() )
    201 			{
    202 				System.out.println( "Waiting for active connections to finish.." );
    203 				Thread.sleep( 500 );
    204 				maxwait -= 500;
    205 			}
    206
    207 			return !hasActiveConnections();
    208 		}
    209
    210 		private boolean hasActiveConnections()
    211 		{
    212 			for( HttpConnection connection : connections )
    213 			{
    214 				if( !connection.isIdle() )
    215 					return true;
    216 			}
    217
    218 			return false;
    219 		}
    220 	}
    221
    222 	private class ServerHandler extends AbstractHandler
    223 	{
    224 		public void handle( String target, HttpServletRequest request,
    225 					HttpServletResponse response, int dispatch ) throws IOException, ServletException
    226 		{
    227 			// find mockService
    228 			Map<String, MockRunner> map = runners.get( request.getLocalPort() );
    229 			if( map != null )
    230 			{
    231 				MockRunner wsdlMockRunner = map.get( request.getPathInfo() );
    232 				if( wsdlMockRunner != null )
    233 				{
    234 					try
    235 					{
    236 						WsdlMockResult result = ( WsdlMockResult ) wsdlMockRunner.dispatchRequest( request, response );
    237 						result.finish();
    238 					}
    239 					catch( Exception e )
    240 					{
    241 						SoapUI.logError( e );
    242
    243 						response.getWriter().print( SoapMessageBuilder.buildFault( "Server", e.getMessage(),
    244 									SoapVersion.Utils.getSoapVersionForContentType( request.getContentType() )));
    245
    246 						throw new ServletException( e );
    247 					}
    248 				}
    249 			}
    250 		}
    251 	}
    252
    253 	public MockRunner [] getMockRunners()
    254 	{
    255 		return mockRunners.toArray( new MockRunner[mockRunners.size()] );
    256 	}
    257 }