1
2
3
4
5
6
7
8
9
10
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
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(), SoapVersion.Soap11 )));
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 }