/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.impl.support;
import com.eviware.soapui.SoapUI;
import com.eviware.soapui.config.BaseMockServiceConfig;
import com.eviware.soapui.impl.rest.mock.RestMockService;
import com.eviware.soapui.impl.wsdl.AbstractTestPropertyHolderWsdlModelItem;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunContext;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
import com.eviware.soapui.impl.wsdl.support.ExternalDependency;
import com.eviware.soapui.impl.wsdl.support.IconAnimator;
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext;
import com.eviware.soapui.impl.wsdl.teststeps.BeanPathPropertySupport;
import com.eviware.soapui.model.ModelItem;
import com.eviware.soapui.model.mock.MockOperation;
import com.eviware.soapui.model.mock.MockRequest;
import com.eviware.soapui.model.mock.MockResponse;
import com.eviware.soapui.model.mock.MockResult;
import com.eviware.soapui.model.mock.MockRunListener;
import com.eviware.soapui.model.mock.MockRunner;
import com.eviware.soapui.model.mock.MockService;
import com.eviware.soapui.model.mock.MockServiceListener;
import com.eviware.soapui.model.support.ModelSupport;
import com.eviware.soapui.settings.HttpSettings;
import com.eviware.soapui.settings.SSLSettings;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.resolver.ResolveContext;
import com.eviware.soapui.support.scripting.ScriptEnginePool;
import com.eviware.soapui.support.scripting.SoapUIScriptEngine;
import com.eviware.soapui.support.scripting.SoapUIScriptEngineRegistry;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public abstract class AbstractMockService<MockOperationType extends MockOperation,
MockServiceConfigType extends BaseMockServiceConfig>
extends AbstractTestPropertyHolderWsdlModelItem<MockServiceConfigType>
implements MockService, HasHelpUrl {
public final static String START_SCRIPT_PROPERTY = AbstractMockService.class.getName() + "@startScript";
public final static String STOP_SCRIPT_PROPERTY = AbstractMockService.class.getName() + "@stopScript";
protected List<MockOperation> mockOperations = new ArrayList<MockOperation>();
private Set<MockRunListener> mockRunListeners = new HashSet<MockRunListener>();
private Set<MockServiceListener> mockServiceListeners = new HashSet<MockServiceListener>();
private MockServiceIconAnimator iconAnimator;
private WsdlMockRunner mockRunner;
private SoapUIScriptEngine startScriptEngine;
private SoapUIScriptEngine stopScriptEngine;
private BeanPathPropertySupport docrootProperty;
private ScriptEnginePool onRequestScriptEnginePool;
private ScriptEnginePool afterRequestScriptEnginePool;
protected AbstractMockService(MockServiceConfigType config, ModelItem parent, String icon) {
super(config, parent, icon);
if (!config.isSetPort() || config.getPort() < 1) {
config.setPort(8080);
}
if (!config.isSetPath()) {
config.setPath("/");
}
if (!config.isSetId()) {
config.setId(ModelSupport.generateModelItemID());
}
initHost(config);
docrootProperty = new BeanPathPropertySupport(this, "docroot");
iconAnimator = new MockServiceIconAnimator();
addMockRunListener(iconAnimator);
}
private void initHost(MockServiceConfigType config) {
try {
if (!config.isSetHost() || !StringUtils.hasContent(config.getHost())) {
config.setHost(InetAddress.getLocalHost().getHostName());
}
} catch (UnknownHostException e) {
SoapUI.logError(e);
}
}
// Implements MockService
@Override
public WsdlProject getProject() {
return (WsdlProject) getParent();
}
@Override
public MockOperationType getMockOperationAt(int index) {
return (MockOperationType) mockOperations.get(index);
}
@Override
public MockOperation getMockOperationByName(String name) {
for (MockOperation operation : mockOperations) {
if (operation.getName() != null && operation.getName().equals(name)) {
return operation;
}
}
return null;
}
public void addMockOperation(MockOperationType mockOperation) {
if (canIAddAMockOperation(mockOperation)) {
mockOperations.add(mockOperation);
} else {
throw new IllegalStateException(mockOperation.getName() + " is not attached to service " + this.getName());
}
}
protected String getProtocol() {
try {
boolean sslEnabled = SoapUI.getSettings().getBoolean(SSLSettings.ENABLE_MOCK_SSL);
String protocol = sslEnabled ? "https://" : "http://";
return protocol;
} catch (Exception e) {
return "http://";
}
}
protected abstract boolean canIAddAMockOperation(MockOperationType mockOperation);
@Override
public int getMockOperationCount() {
return mockOperations.size();
}
@Override
public int getPort() {
return getConfig().getPort();
}
@Override
public String getPath() {
return getConfig().getPath();
}
@Override
public void removeMockOperation(MockOperation mockOperation) {
int ix = mockOperations.indexOf(mockOperation);
if (ix == -1) {
throw new RuntimeException("Unknown MockOperation specified to removeMockOperation");
}
mockOperations.remove(ix);
fireMockOperationRemoved(mockOperation);
mockOperation.release();
if (this instanceof WsdlMockService) {
((WsdlMockService) this).getConfig().removeMockOperation(ix);
} else if (this instanceof RestMockService) {
((RestMockService) this).getConfig().removeRestMockAction(ix);
}
}
public String getLocalEndpoint() {
String host = getHost();
if (StringUtils.isNullOrEmpty(host)) {
host = "127.0.0.1";
}
return getProtocol() + host + ":" + getPort() + getPath();
}
@Override
public String getHost() {
return getConfig().getHost();
}
public void setHost(String host) {
getConfig().setHost(host);
}
@Override
public void setPort(int port) {
int oldPort = getPort();
getConfig().setPort(port);
notifyPropertyChanged(PORT_PROPERTY, oldPort, port);
}
@Override
public void setPath(String path) {
String oldPath = getPath();
getConfig().setPath(path);
notifyPropertyChanged(PATH_PROPERTY, oldPath, path);
}
@Override
public WsdlMockRunner start() throws Exception {
return start(null);
}
@Override
public void startIfConfigured() throws Exception {
if (SoapUI.getSettings().getBoolean(HttpSettings.START_MOCK_SERVICE)) {
start();
}
}
@Override
public boolean getBindToHostOnly() {
return getConfig().getBindToHostOnly();
}
public void setBindToHostOnly(boolean bindToHostOnly) {
getConfig().setBindToHostOnly(bindToHostOnly);
}
// TODO: think about naming - this does not start nothing.....
public WsdlMockRunner start(WsdlTestRunContext context) throws Exception {
String path = getPath();
if (path == null || path.trim().length() == 0 || path.trim().charAt(0) != '/') {
throw new Exception("Invalid path; must start with '/'");
}
mockRunner = new WsdlMockRunner(this, context);
return mockRunner;
}
@Override
public void addMockRunListener(MockRunListener listener) {
mockRunListeners.add(listener);
}
@Override
public void removeMockRunListener(MockRunListener listener) {
mockRunListeners.remove(listener);
}
@Override
public void addMockServiceListener(MockServiceListener listener) {
mockServiceListeners.add(listener);
}
@Override
public void removeMockServiceListener(MockServiceListener listener) {
mockServiceListeners.remove(listener);
}
@Override
public WsdlMockRunner getMockRunner() {
return mockRunner;
}
public void setMockRunner(WsdlMockRunner mockRunner) {
this.mockRunner = mockRunner;
}
@Override
public MockRunListener[] getMockRunListeners() {
return mockRunListeners.toArray(new MockRunListener[mockRunListeners.size()]);
}
public MockServiceListener[] getMockServiceListeners() {
return mockServiceListeners.toArray(new MockServiceListener[mockServiceListeners.size()]);
}
@Override
public List<MockOperation> getMockOperationList() {
return Collections.unmodifiableList(new ArrayList<MockOperation>(mockOperations));
}
protected List<MockOperation> getMockOperations() {
return mockOperations;
}
@Override
public void fireMockOperationAdded(MockOperation mockOperation) {
for (MockServiceListener listener : getMockServiceListeners()) {
listener.mockOperationAdded(mockOperation);
}
}
@Override
public void fireMockOperationRemoved(MockOperation mockOperation) {
for (MockServiceListener listener : getMockServiceListeners()) {
listener.mockOperationRemoved(mockOperation);
}
}
@Override
public void fireMockResponseAdded(MockResponse mockResponse) {
for (MockServiceListener listener : getMockServiceListeners()) {
listener.mockResponseAdded(mockResponse);
}
}
@Override
public void fireMockResponseRemoved(MockResponse mockResponse) {
for (MockServiceListener listener : getMockServiceListeners()) {
listener.mockResponseRemoved(mockResponse);
}
}
@Override
public void release() {
super.release();
mockServiceListeners.clear();
if (mockRunner != null) {
if (mockRunner.isRunning()) {
mockRunner.stop();
}
if (mockRunner != null) {
mockRunner.release();
}
}
if (onRequestScriptEnginePool != null) {
onRequestScriptEnginePool.release();
}
if (afterRequestScriptEnginePool != null) {
afterRequestScriptEnginePool.release();
}
if (startScriptEngine != null) {
startScriptEngine.release();
}
if (stopScriptEngine != null) {
stopScriptEngine.release();
}
}
@Override
public void setStartScript(String script) {
String oldScript = getStartScript();
if (!getConfig().isSetStartScript()) {
getConfig().addNewStartScript();
}
getConfig().getStartScript().setStringValue(script);
if (startScriptEngine != null) {
startScriptEngine.setScript(script);
}
notifyPropertyChanged(START_SCRIPT_PROPERTY, oldScript, script);
}
@Override
public String getStartScript() {
return getConfig().isSetStartScript() ? getConfig().getStartScript().getStringValue() : null;
}
@Override
public void setStopScript(String script) {
String oldScript = getStopScript();
if (!getConfig().isSetStopScript()) {
getConfig().addNewStopScript();
}
getConfig().getStopScript().setStringValue(script);
if (stopScriptEngine != null) {
stopScriptEngine.setScript(script);
}
notifyPropertyChanged(STOP_SCRIPT_PROPERTY, oldScript, script);
}
@Override
public String getStopScript() {
return getConfig().isSetStopScript() ? getConfig().getStopScript().getStringValue() : null;
}
@Override
public Object runStartScript(WsdlMockRunContext runContext, MockRunner runner) throws Exception {
String script = getStartScript();
if (StringUtils.isNullOrEmpty(script)) {
return null;
}
if (startScriptEngine == null) {
startScriptEngine = SoapUIScriptEngineRegistry.create(this);
startScriptEngine.setScript(script);
}
startScriptEngine.setVariable("context", runContext);
startScriptEngine.setVariable("mockRunner", runner);
startScriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
return startScriptEngine.run();
}
@Override
public Object runStopScript(WsdlMockRunContext runContext, MockRunner runner) throws Exception {
String script = getStopScript();
if (StringUtils.isNullOrEmpty(script)) {
return null;
}
if (stopScriptEngine == null) {
stopScriptEngine = SoapUIScriptEngineRegistry.create(this);
stopScriptEngine.setScript(script);
}
stopScriptEngine.setVariable("context", runContext);
stopScriptEngine.setVariable("mockRunner", runner);
stopScriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
return stopScriptEngine.run();
}
@Override
public void setOnRequestScript(String script) {
String oldScript = getOnRequestScript();
if (!getConfig().isSetOnRequestScript()) {
getConfig().addNewOnRequestScript();
}
getConfig().getOnRequestScript().setStringValue(script);
if (onRequestScriptEnginePool != null) {
onRequestScriptEnginePool.setScript(script);
}
notifyPropertyChanged("onRequestScript", oldScript, script);
}
@Override
public String getOnRequestScript() {
return getConfig().isSetOnRequestScript() ? getConfig().getOnRequestScript().getStringValue() : null;
}
@Override
public void setAfterRequestScript(String script) {
String oldScript = getAfterRequestScript();
if (!getConfig().isSetAfterRequestScript()) {
getConfig().addNewAfterRequestScript();
}
getConfig().getAfterRequestScript().setStringValue(script);
if (afterRequestScriptEnginePool != null) {
afterRequestScriptEnginePool.setScript(script);
}
notifyPropertyChanged("afterRequestScript", oldScript, script);
}
@Override
public String getAfterRequestScript() {
return getConfig().isSetAfterRequestScript() ? getConfig().getAfterRequestScript().getStringValue() : null;
}
@Override
public Object runOnRequestScript(WsdlMockRunContext runContext, MockRequest mockRequest) throws Exception {
String script = getOnRequestScript();
if (StringUtils.isNullOrEmpty(script)) {
return null;
}
if (onRequestScriptEnginePool == null) {
onRequestScriptEnginePool = new ScriptEnginePool(this);
onRequestScriptEnginePool.setScript(script);
}
SoapUIScriptEngine scriptEngine = onRequestScriptEnginePool.getScriptEngine();
try {
scriptEngine.setVariable("context", runContext);
scriptEngine.setVariable("mockRequest", mockRequest);
scriptEngine.setVariable("mockRunner", getMockRunner());
scriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
return scriptEngine.run();
} finally {
onRequestScriptEnginePool.returnScriptEngine(scriptEngine);
}
}
@Override
public Object runAfterRequestScript(WsdlMockRunContext runContext, MockResult mockResult) throws Exception {
String script = getAfterRequestScript();
if (StringUtils.isNullOrEmpty(script)) {
return null;
}
if (afterRequestScriptEnginePool == null) {
afterRequestScriptEnginePool = new ScriptEnginePool(this);
afterRequestScriptEnginePool.setScript(script);
}
SoapUIScriptEngine scriptEngine = afterRequestScriptEnginePool.getScriptEngine();
try {
scriptEngine.setVariable("context", runContext);
scriptEngine.setVariable("mockResult", mockResult);
scriptEngine.setVariable("mockRunner", getMockRunner());
scriptEngine.setVariable("log", SoapUI.ensureGroovyLog());
return scriptEngine.run();
} finally {
afterRequestScriptEnginePool.returnScriptEngine(scriptEngine);
}
}
public void setDocroot(String docroot) {
docrootProperty.set(docroot, true);
}
public String getDocroot() {
return docrootProperty.get();
}
@Override
public void addExternalDependencies(List<ExternalDependency> dependencies) {
super.addExternalDependencies(dependencies);
//Disable since ProjectExporter.packageAll doesn't seem to handle folders
//dependencies.add( new MockServiceExternalDependency( docrootProperty ) );
}
@Override
public void resolve(ResolveContext<?> context) {
super.resolve(context);
docrootProperty.resolveFile(context, "Missing MockService docroot");
}
public boolean isDispatchResponseMessages() {
return getConfig().getDispatchResponseMessages();
}
public void setDispatchResponseMessages(boolean dispatchResponseMessages) {
boolean old = isDispatchResponseMessages();
getConfig().setDispatchResponseMessages(dispatchResponseMessages);
notifyPropertyChanged("dispatchResponseMessages", old, dispatchResponseMessages);
}
public abstract String getIconName();
public void fireOnMockResult(Object result) {
if (result != null && result instanceof MockResult) {
for (MockRunListener listener : getMockRunListeners()) {
listener.onMockResult((MockResult) result);
}
}
}
private class MockServiceIconAnimator
extends IconAnimator<MockService>
implements MockRunListener {
public MockServiceIconAnimator() {
super(AbstractMockService.this, getIconName(), getIconName(), 4);
}
public MockResult onMockRequest(MockRunner runner, HttpServletRequest request, HttpServletResponse response) {
return null;
}
public void onMockResult(MockResult result) {
}
public void onMockRunnerStart(MockRunner mockRunner) {
start();
}
public void onMockRunnerStop(MockRunner mockRunner) {
stop();
AbstractMockService.this.mockRunner = null;
}
}
}