1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.monitor;
14
15 import com.eviware.soapui.SoapUI;
16 import com.eviware.soapui.impl.wsdl.mock.DispatchException;
17 import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
18 import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
19 import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
20 import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
21 import com.eviware.soapui.model.mock.MockResult;
22 import com.eviware.soapui.model.mock.MockRunner;
23 import com.eviware.soapui.model.mock.MockService;
24 import com.eviware.soapui.settings.HttpSettings;
25 import com.eviware.soapui.settings.SSLSettings;
26 import com.eviware.soapui.support.StringUtils;
27 import com.eviware.soapui.support.UISupport;
28 import com.eviware.soapui.support.log.JettyLogger;
29 import org.apache.log4j.Logger;
30 import org.mortbay.jetty.HttpConnection;
31 import org.mortbay.jetty.Server;
32 import org.mortbay.jetty.handler.AbstractHandler;
33 import org.mortbay.jetty.nio.SelectChannelConnector;
34 import org.mortbay.jetty.security.SslSocketConnector;
35 import org.mortbay.thread.BoundedThreadPool;
36
37 import javax.servlet.ServletException;
38 import javax.servlet.http.HttpServletRequest;
39 import javax.servlet.http.HttpServletResponse;
40 import java.io.IOException;
41 import java.io.PrintWriter;
42 import java.util.*;
43
44 /***
45 * Core Mock-Engine hosting a Jetty web server
46 *
47 * @author ole.matzura
48 */
49
50 public class MockEngine
51 {
52 public final static Logger log = Logger.getLogger(MockEngine.class);
53
54 private Server server;
55 private Map<Integer, Map<String, List<MockRunner>>> runners = new HashMap<Integer, Map<String, List<MockRunner>>>();
56 private Map<Integer, SoapUIConnector> connectors = new HashMap<Integer, SoapUIConnector>();
57 private List<MockRunner> mockRunners = new ArrayList<MockRunner>();
58
59 private SslSocketConnector sslConnector;
60
61 public MockEngine()
62 {
63 System.setProperty("org.mortbay.log.class", JettyLogger.class.getName());
64 }
65
66 public boolean hasRunningMock(MockService mockService)
67 {
68 for (MockRunner runner : mockRunners)
69 if (runner.getMockService() == mockService)
70 return true;
71
72 return false;
73 }
74
75 public synchronized void startMockService(MockRunner runner) throws Exception
76 {
77 if (server == null)
78 initServer();
79
80 WsdlMockService mockService = (WsdlMockService) runner.getMockService();
81 int port = mockService.getPort();
82
83 if (!runners.containsKey(port))
84 {
85 SoapUIConnector connector = new SoapUIConnector();
86
87 connector.setPort(port);
88 if (sslConnector != null)
89 connector.setConfidentialPort(sslConnector.getPort());
90
91 if (mockService.getBindToHostOnly())
92 {
93 String host = mockService.getHost();
94 if (StringUtils.hasContent(host))
95 {
96 connector.setHost(host);
97 }
98 }
99
100 boolean wasRunning = server.isRunning();
101
102 if (wasRunning)
103 {
104 server.stop();
105 }
106
107 server.addConnector(connector);
108 try
109 {
110 server.start();
111 }
112 catch (RuntimeException e)
113 {
114 UISupport.showErrorMessage(e);
115
116 server.removeConnector(connector);
117 if (wasRunning)
118 {
119 server.start();
120 return;
121 }
122 }
123
124 connectors.put(new Integer(port), connector);
125 runners.put(new Integer(port), new HashMap<String, List<MockRunner>>());
126 }
127
128 Map<String, List<MockRunner>> map = runners.get(port);
129 String path = mockService.getPath();
130 if (!map.containsKey(path))
131 {
132 map.put(path, new ArrayList<MockRunner>());
133 }
134 map.get(path).add(runner);
135 mockRunners.add(runner);
136
137 log.info("Started mockService [" + mockService.getName() + "] on port [" + port + "] at path [" + path + "]");
138 }
139
140 private void initServer() throws Exception
141 {
142 server = new Server();
143 BoundedThreadPool threadPool = new BoundedThreadPool();
144 threadPool.setMaxThreads(100);
145 server.setThreadPool(threadPool);
146 server.setHandler(new ServerHandler());
147
148 if (SoapUI.getSettings().getBoolean(SSLSettings.ENABLE_MOCK_SSL))
149 {
150 sslConnector = new SslSocketConnector();
151 sslConnector.setKeystore(SoapUI.getSettings().getString(SSLSettings.MOCK_KEYSTORE, null));
152 sslConnector.setPassword(SoapUI.getSettings().getString(SSLSettings.MOCK_PASSWORD, null));
153 sslConnector.setKeyPassword(SoapUI.getSettings().getString(SSLSettings.MOCK_KEYSTORE_PASSWORD, null));
154 sslConnector.setTruststore(SoapUI.getSettings().getString(SSLSettings.MOCK_TRUSTSTORE, null));
155 sslConnector.setTrustPassword(SoapUI.getSettings().getString(SSLSettings.MOCK_TRUSTSTORE_PASSWORD, null));
156 sslConnector.setMaxIdleTime(30000);
157 sslConnector.setPort((int) SoapUI.getSettings().getLong(SSLSettings.MOCK_PORT, 443));
158 sslConnector.setNeedClientAuth(SoapUI.getSettings().getBoolean(SSLSettings.CLIENT_AUTHENTICATION));
159
160 server.addConnector(sslConnector);
161 }
162 }
163
164 public synchronized void stopMockService(WsdlMockRunner runner)
165 {
166 MockService mockService = runner.getMockService();
167 final Integer port = new Integer(mockService.getPort());
168 Map<String, List<MockRunner>> map = runners.get(port);
169
170 map.get(mockService.getPath()).remove(runner);
171 mockRunners.remove(runner);
172
173 log.info("Stopped MockService [" + mockService.getName() + "] on port [" + port + "]");
174
175 if (map.isEmpty() && !SoapUI.getSettings().getBoolean(HttpSettings.LEAVE_MOCKENGINE))
176 {
177 SoapUIConnector connector = (SoapUIConnector) connectors.get(port);
178 if (connector == null)
179 {
180 log.warn("Missing connectors on port [" + port + "]");
181 return;
182 }
183
184 try
185 {
186 log.info("Stopping connector on port " + port);
187 if (!connector.waitUntilIdle(5000))
188 {
189 log.warn("Failed to wait for idle.. stopping connector anyway..");
190 }
191 connector.stop();
192 }
193 catch (Exception e)
194 {
195 SoapUI.logError(e);
196 }
197 server.removeConnector(connector);
198 runners.remove(port);
199 if (runners.isEmpty())
200 {
201 try
202 {
203 log.info("No more connectors.. stopping server");
204 server.stop();
205 if (sslConnector != null)
206 {
207 server.removeConnector(sslConnector);
208 sslConnector.stop();
209 sslConnector = null;
210 }
211 }
212 catch (Exception e)
213 {
214 SoapUI.logError(e);
215 }
216 }
217 }
218 }
219
220 private class SoapUIConnector extends SelectChannelConnector
221 {
222 private Set<HttpConnection> connections = new HashSet<HttpConnection>();
223
224 @Override
225 protected void connectionClosed(HttpConnection arg0)
226 {
227 super.connectionClosed(arg0);
228 connections.remove(arg0);
229 }
230
231 @Override
232 protected void connectionOpened(HttpConnection arg0)
233 {
234 super.connectionOpened(arg0);
235 connections.add(arg0);
236 }
237
238 public boolean waitUntilIdle(long maxwait) throws Exception
239 {
240 while (maxwait > 0 && hasActiveConnections())
241 {
242 System.out.println("Waiting for active connections to finish..");
243 Thread.sleep(500);
244 maxwait -= 500;
245 }
246
247 return !hasActiveConnections();
248 }
249
250 private boolean hasActiveConnections()
251 {
252 for (HttpConnection connection : connections)
253 {
254 if (!connection.isIdle())
255 return true;
256 }
257
258 return false;
259 }
260 }
261
262 private class ServerHandler extends AbstractHandler
263 {
264 public void handle(String target, HttpServletRequest request, HttpServletResponse response, int dispatch)
265 throws IOException, ServletException
266 {
267
268 Map<String, List<MockRunner>> map = runners.get(request.getLocalPort());
269
270
271 if (map == null && sslConnector != null && request.getLocalPort() == sslConnector.getPort())
272 {
273 for (Map<String, List<MockRunner>> runnerMap : runners.values())
274 {
275 if (runnerMap.containsKey(request.getPathInfo()))
276 {
277 map = runnerMap;
278 break;
279 }
280 }
281 }
282
283 if (map != null)
284 {
285 List<MockRunner> wsdlMockRunners = map.get(request.getPathInfo());
286 if (wsdlMockRunners == null && request.getMethod().equals("GET"))
287 {
288 for (String root : map.keySet())
289 {
290 if (request.getPathInfo().startsWith(root))
291 {
292 wsdlMockRunners = map.get(root);
293 }
294 }
295 }
296
297 if (wsdlMockRunners != null)
298 {
299 synchronized (wsdlMockRunners)
300 {
301 try
302 {
303 DispatchException ex = null;
304
305 for (MockRunner wsdlMockRunner : wsdlMockRunners)
306 {
307 try
308 {
309 MockResult result = wsdlMockRunner.dispatchRequest(request, response);
310 if( result != null )
311 result.finish();
312
313
314 break;
315 }
316 catch (DispatchException e)
317 {
318 log.debug(wsdlMockRunner.getMockService().getName()
319 + " was unable to dispatch mock request ", e);
320
321 ex = e;
322 }
323 }
324
325 if( ex != null )
326 throw ex;
327 }
328 catch (Exception e)
329 {
330 SoapUI.logError(e);
331
332 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
333 response.setContentType("text/html");
334 response.getWriter().print(
335 SoapMessageBuilder.buildFault("Server", e.getMessage(), SoapVersion.Utils
336 .getSoapVersionForContentType(request.getContentType(), SoapVersion.Soap11)));
337 response.flushBuffer();
338
339
340 }
341 }
342 }
343 else
344 {
345 printMockServiceList(response);
346 }
347 }
348 else
349 {
350 printMockServiceList(response);
351 }
352 }
353
354 private void printMockServiceList(HttpServletResponse response) throws IOException
355 {
356 response.setStatus(HttpServletResponse.SC_OK);
357 response.setContentType("text/html");
358
359 MockRunner[] mockRunners = getMockRunners();
360 PrintWriter out = response.getWriter();
361 out.print("<html><body><p>There are currently " + mockRunners.length + " running soapUI MockServices</p><ul>");
362
363 for (MockRunner mockRunner : mockRunners)
364 {
365 out.print("<li><a href=\"");
366 out.print(((WsdlMockService) mockRunner.getMockService()).getPath() + "?WSDL");
367 out.print("\">" + mockRunner.getMockService().getName() + "</a></li>");
368 }
369
370 out.print("</ul></p></body></html>");
371 response.flushBuffer();
372 }
373 }
374
375 public MockRunner[] getMockRunners()
376 {
377 return mockRunners.toArray(new MockRunner[mockRunners.size()]);
378 }
379 }