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