001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.monitor;
014:
015: import java.io.IOException;
016: import java.util.ArrayList;
017: import java.util.HashMap;
018: import java.util.HashSet;
019: import java.util.List;
020: import java.util.Map;
021: import java.util.Set;
022:
023: import javax.servlet.ServletException;
024: import javax.servlet.http.HttpServletRequest;
025: import javax.servlet.http.HttpServletResponse;
026:
027: import org.apache.log4j.Logger;
028: import org.mortbay.jetty.HttpConnection;
029: import org.mortbay.jetty.Server;
030: import org.mortbay.jetty.handler.AbstractHandler;
031: import org.mortbay.jetty.nio.SelectChannelConnector;
032: import org.mortbay.thread.BoundedThreadPool;
033:
034: import com.eviware.soapui.SoapUI;
035: import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult;
036: import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
037: import com.eviware.soapui.impl.wsdl.support.soap.SoapMessageBuilder;
038: import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
039: import com.eviware.soapui.model.mock.MockRunner;
040: import com.eviware.soapui.model.mock.MockService;
041: import com.eviware.soapui.support.UISupport;
042: import com.eviware.soapui.support.log.JettyLogger;
043:
044: /**
045: * Core Mock-Engine hosting a Jetty web server
046: *
047: * @author ole.matzura
048: */
049:
050: public class MockEngine {
051: private final static Logger log = Logger
052: .getLogger(MockEngine.class);
053:
054: private Server server;
055: private Map<Integer, Map<String, MockRunner>> runners = new HashMap<Integer, Map<String, MockRunner>>();
056: private Map<Integer, SoapUIConnector> connectors = new HashMap<Integer, SoapUIConnector>();
057: private List<MockRunner> mockRunners = new ArrayList<MockRunner>();
058:
059: public MockEngine() {
060: System.setProperty("org.mortbay.log.class", JettyLogger.class
061: .getName());
062: }
063:
064: public boolean hasRunningMock(MockService mockService) {
065: for (MockRunner runner : mockRunners)
066: if (runner.getMockService() == mockService)
067: return true;
068:
069: return false;
070: }
071:
072: public void startMockService(MockRunner runner) throws Exception {
073: if (server == null)
074: initServer();
075:
076: MockService mockService = runner.getMockService();
077: int port = mockService.getPort();
078:
079: if (!runners.containsKey(port)) {
080: SoapUIConnector connector = new SoapUIConnector();
081:
082: connector.setPort(port);
083: boolean wasRunning = server.isRunning();
084:
085: if (wasRunning) {
086: server.stop();
087: }
088:
089: server.addConnector(connector);
090: try {
091: server.start();
092: } catch (RuntimeException e) {
093: UISupport.showErrorMessage(e);
094:
095: server.removeConnector(connector);
096: if (wasRunning) {
097: server.start();
098: return;
099: }
100: }
101:
102: connectors.put(new Integer(port), connector);
103: runners.put(new Integer(port),
104: new HashMap<String, MockRunner>());
105: }
106:
107: Map<String, MockRunner> map = runners.get(port);
108: String path = mockService.getPath();
109: map.put(path, runner);
110: mockRunners.add(runner);
111:
112: log.info("Started mockService [" + mockService.getName()
113: + "] on port [" + port + "] at path [" + path + "]");
114: }
115:
116: private void initServer() throws Exception {
117: server = new Server();
118: BoundedThreadPool threadPool = new BoundedThreadPool();
119: threadPool.setMaxThreads(100);
120: server.setThreadPool(threadPool);
121:
122: server.setHandler(new ServerHandler());
123: }
124:
125: public void stopMockService(WsdlMockRunner runner) {
126: MockService mockService = runner.getMockService();
127: final Integer port = new Integer(mockService.getPort());
128: Map<String, MockRunner> map = runners.get(port);
129:
130: map.remove(mockService.getPath());
131: mockRunners.remove(runner);
132:
133: if (map.isEmpty()) {
134: SoapUIConnector connector = (SoapUIConnector) connectors
135: .get(port);
136: if (connector == null) {
137: log.warn("Missing connectors on port [" + port + "]");
138: return;
139: }
140:
141: try {
142: log.info("Stopping connector on port " + port);
143: if (!connector.waitUntilIdle(5000)) {
144: log
145: .warn("Failed to wait for idle.. stopping connector anyway..");
146: }
147: connector.stop();
148: } catch (Exception e) {
149: SoapUI.logError(e);
150: }
151: server.removeConnector(connector);
152: runners.remove(port);
153: if (runners.isEmpty()) {
154: try {
155: log.info("No more connectors.. stopping server");
156: server.stop();
157: } catch (Exception e) {
158: SoapUI.logError(e);
159: }
160: }
161: }
162: }
163:
164: private class SoapUIConnector extends SelectChannelConnector {
165: private Set<HttpConnection> connections = new HashSet<HttpConnection>();
166:
167: @Override
168: protected void connectionClosed(HttpConnection arg0) {
169: super .connectionClosed(arg0);
170: connections.remove(arg0);
171: }
172:
173: @Override
174: protected void connectionOpened(HttpConnection arg0) {
175: super .connectionOpened(arg0);
176: connections.add(arg0);
177: }
178:
179: public boolean waitUntilIdle(long maxwait) throws Exception {
180: while (maxwait > 0 && hasActiveConnections()) {
181: System.out
182: .println("Waiting for active connections to finish..");
183: Thread.sleep(500);
184: maxwait -= 500;
185: }
186:
187: return !hasActiveConnections();
188: }
189:
190: private boolean hasActiveConnections() {
191: for (HttpConnection connection : connections) {
192: if (!connection.isIdle())
193: return true;
194: }
195:
196: return false;
197: }
198: }
199:
200: private class ServerHandler extends AbstractHandler {
201: public void handle(String target, HttpServletRequest request,
202: HttpServletResponse response, int dispatch)
203: throws IOException, ServletException {
204: // find mockService
205: Map<String, MockRunner> map = runners.get(request
206: .getLocalPort());
207: if (map != null) {
208: MockRunner wsdlMockRunner = map.get(request
209: .getPathInfo());
210: if (wsdlMockRunner != null) {
211: try {
212: WsdlMockResult result = (WsdlMockResult) wsdlMockRunner
213: .dispatchRequest(request, response);
214: result.finish();
215: } catch (Exception e) {
216: SoapUI.logError(e);
217:
218: response
219: .getWriter()
220: .print(
221: SoapMessageBuilder
222: .buildFault(
223: "Server",
224: e.getMessage(),
225: SoapVersion.Utils
226: .getSoapVersionForContentType(request
227: .getContentType())));
228:
229: throw new ServletException(e);
230: }
231: }
232: }
233: }
234: }
235:
236: public MockRunner[] getMockRunners() {
237: return mockRunners.toArray(new MockRunner[mockRunners.size()]);
238: }
239: }
|