/*
* 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;
import com.eviware.soapui.config.SoapuiSettingsDocumentConfig;
import com.eviware.soapui.impl.settings.XmlBeansSettingsImpl;
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport;
import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionUtils;
import com.eviware.soapui.model.settings.Settings;
import com.eviware.soapui.monitor.JettyMockEngine;
import com.eviware.soapui.monitor.MockEngine;
import com.eviware.soapui.plugins.PluginManager;
import com.eviware.soapui.security.registry.SecurityScanRegistry;
import com.eviware.soapui.settings.HttpSettings;
import com.eviware.soapui.settings.ProxySettings;
import com.eviware.soapui.settings.SecuritySettings;
import com.eviware.soapui.settings.UISettings;
import com.eviware.soapui.settings.VersionUpdateSettings;
import com.eviware.soapui.settings.WSISettings;
import com.eviware.soapui.settings.WsaSettings;
import com.eviware.soapui.settings.WsdlSettings;
import com.eviware.soapui.support.SecurityScanUtil;
import com.eviware.soapui.support.StringUtils;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.action.SoapUIActionRegistry;
import com.eviware.soapui.support.factory.SoapUIFactoryRegistry;
import com.eviware.soapui.support.listener.SoapUIListenerRegistry;
import com.eviware.soapui.support.types.StringList;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.ssl.OpenSSL;
import org.apache.log4j.Logger;
import org.apache.log4j.xml.DOMConfigurator;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPasswordField;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.GeneralSecurityException;
import java.util.TimerTask;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
/**
* Initializes core objects. Transform to a Spring "ApplicationContext"?
*
* @author ole.matzura
*/
public class DefaultSoapUICore implements SoapUICore {
public static Logger log;
private boolean logIsInitialized;
private String root;
protected SoapuiSettingsDocumentConfig settingsDocument;
private volatile MockEngine mockEngine;
private XmlBeansSettingsImpl settings;
private SoapUIListenerRegistry listenerRegistry;
private SoapUIActionRegistry actionRegistry;
private SoapUIFactoryRegistry factoryRegistry;
private long lastSettingsLoad = 0;
private String settingsFile;
private String password;
protected boolean initialImport;
private TimerTask settingsWatcher;
private SoapUIExtensionClassLoader extClassLoader;
private PluginManager pluginManager;
public boolean isSavingSettings;
protected SecurityScanRegistry securityScanRegistry;
public boolean getInitialImport() {
return initialImport;
}
public void setInitialImport(boolean initialImport) {
this.initialImport = initialImport;
}
public static DefaultSoapUICore createDefault() {
return new DefaultSoapUICore(null, DEFAULT_SETTINGS_FILE);
}
public DefaultSoapUICore() {
}
/*
* this method is added for enabling settings password (like in core) all the
* way down in hierarchy boolean settingPassword is a dummy parameter, because
* the constructor with only one string parameter already existed
*/
public DefaultSoapUICore(boolean settingPassword, String soapUISettingsPassword) {
this.password = soapUISettingsPassword;
}
public DefaultSoapUICore(String root) {
this.root = root;
}
public DefaultSoapUICore(String root, String settingsFile) {
this(root);
init(settingsFile);
}
public DefaultSoapUICore(String root, String settingsFile, String password) {
this(root);
this.password = password;
init(settingsFile);
}
public void init(String settingsFile) {
initLog();
SoapUI.setSoapUICore(this);
loadExternalLibraries();
initSettings(settingsFile == null ? DEFAULT_SETTINGS_FILE : settingsFile);
initExtensions(getExtensionClassLoader());
initCoreComponents();
loadPlugins();
// this is to provoke initialization
SoapVersion.Soap11.equals(SoapVersion.Soap12);
}
protected void loadPlugins() {
File pluginDirectory = new File(System.getProperty("soapui.home"), "plugins");
File[] pluginFiles = pluginDirectory.listFiles();
if (pluginFiles != null) {
for (File pluginFile : pluginFiles) {
log.info("Adding plugin from [" + pluginFile.getAbsolutePath() + "]");
try {
loadOldStylePluginFrom(pluginFile);
} catch (Throwable e) {
log.warn("Could not load plugin from file [" + pluginFile + "]");
}
}
}
pluginManager = new PluginManager(getFactoryRegistry(), getActionRegistry(), getListenerRegistry());
pluginManager.loadPlugins();
log.info("All plugins loaded");
}
protected void initExtensions(ClassLoader extensionClassLoader) {
/* We break the general rule that you shouldn't catch Throwable, because we don't want extensions to crash SoapUI. */
try {
String extDir = System.getProperty("soapui.ext.listeners");
addExternalListeners(FilenameUtils.normalize(extDir != null ? extDir : root == null ? "listeners" :
root + File.separatorChar + "listeners"), extensionClassLoader);
} catch (Throwable e) {
SoapUI.logError(e, "Couldn't load external listeners");
}
try {
String factoriesDir = System.getProperty("soapui.ext.factories");
addExternalFactories(FilenameUtils.normalize(factoriesDir != null ? factoriesDir : root == null ? "factories" :
root + File.separatorChar + "factories"), extensionClassLoader);
} catch (Throwable e) {
SoapUI.logError(e, "Couldn't load external factories");
}
}
protected void initCoreComponents() {
}
public void loadOldStylePluginFrom(File pluginFile) throws IOException {
JarFile jarFile = new JarFile(pluginFile);
// add jar to our extension classLoader
SoapUIExtensionClassLoader extensionClassLoader = getExtensionClassLoader();
extensionClassLoader.addFile(pluginFile);
// look for factories
JarEntry entry = jarFile.getJarEntry("META-INF/factories.xml");
if (entry != null) {
getFactoryRegistry().addConfig(jarFile.getInputStream(entry), extensionClassLoader);
}
// look for listeners
entry = jarFile.getJarEntry("META-INF/listeners.xml");
if (entry != null) {
getListenerRegistry().addConfig(jarFile.getInputStream(entry), extensionClassLoader);
}
// look for actions
entry = jarFile.getJarEntry("META-INF/actions.xml");
if (entry != null) {
getActionRegistry().addConfig(jarFile.getInputStream(entry), extensionClassLoader);
}
// add jar to resource classloader so embedded images can be found with UISupport.loadImageIcon(..)
UISupport.addResourceClassLoader(new URLClassLoader(new URL[]{pluginFile.toURI().toURL()}));
}
public String getRoot() {
if (root == null || root.length() == 0) {
root = System.getProperty("soapui.home", new File(".").getAbsolutePath());
}
return FilenameUtils.normalize(root);
}
protected Settings initSettings(String fileName) {
// TODO Why try to load settings from current directory before using root?
// This caused a bug in Eclipse:
// https://sourceforge.net/tracker/?func=detail&atid=737763&aid=2620284&group_id=136013
File settingsFile = new File(fileName).exists() ? new File(fileName) : null;
try {
if (settingsFile == null) {
settingsFile = new File(new File(getRoot()), DEFAULT_SETTINGS_FILE);
if (!settingsFile.exists()) {
settingsFile = new File(new File(System.getProperty("user.home", ".")), DEFAULT_SETTINGS_FILE);
lastSettingsLoad = 0;
}
} else {
settingsFile = new File(fileName);
if (!settingsFile.getAbsolutePath().equals(this.settingsFile)) {
lastSettingsLoad = 0;
}
}
if (!settingsFile.exists()) {
if (settingsDocument == null) {
log.info("Creating new settings at [" + settingsFile.getAbsolutePath() + "]");
settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
setInitialImport(true);
}
lastSettingsLoad = System.currentTimeMillis();
} else if (settingsFile.lastModified() > lastSettingsLoad) {
settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse(settingsFile);
byte[] encryptedContent = settingsDocument.getSoapuiSettings().getEncryptedContent();
if (encryptedContent != null) {
char[] password = null;
if (this.password == null) {
// swing element -!! uh!
JPasswordField passwordField = new JPasswordField();
JLabel qLabel = new JLabel("Password");
JOptionPane.showConfirmDialog(null, new Object[]{qLabel, passwordField}, "Global Settings",
JOptionPane.OK_CANCEL_OPTION);
password = passwordField.getPassword();
} else {
password = this.password.toCharArray();
}
String encryptionAlgorithm = settingsDocument.getSoapuiSettings().getEncryptedContentAlgorithm();
byte[] data = OpenSSL.decrypt(StringUtils.isNullOrEmpty(encryptionAlgorithm) ? "des3" : encryptionAlgorithm, password, encryptedContent);
try {
settingsDocument = SoapuiSettingsDocumentConfig.Factory.parse(new String(data, "UTF-8"));
} catch (Exception e) {
log.warn("Wrong password.");
JOptionPane.showMessageDialog(null, "Wrong password, creating backup settings file [ "
+ settingsFile.getAbsolutePath() + ".bak.xml. ]\nSwitch to default settings.",
"Error - Wrong Password", JOptionPane.ERROR_MESSAGE);
settingsDocument.save(new File(settingsFile.getAbsolutePath() + ".bak.xml"));
throw e;
}
}
log.info("initialized soapui-settings from [" + settingsFile.getAbsolutePath() + "]");
lastSettingsLoad = settingsFile.lastModified();
if (settingsWatcher == null) {
settingsWatcher = new SettingsWatcher();
SoapUI.getSoapUITimer().scheduleAtFixedRate(settingsWatcher, 10000, 10000);
}
}
} catch (Exception e) {
log.warn("Failed to load settings from [" + e.getMessage() + "], creating new");
settingsDocument = SoapuiSettingsDocumentConfig.Factory.newInstance();
lastSettingsLoad = 0;
}
if (settingsDocument.getSoapuiSettings() == null) {
settingsDocument.addNewSoapuiSettings();
settings = new XmlBeansSettingsImpl(null, null, settingsDocument.getSoapuiSettings());
initDefaultSettings(settings);
} else {
settings = new XmlBeansSettingsImpl(null, null, settingsDocument.getSoapuiSettings());
}
this.settingsFile = settingsFile.getAbsolutePath();
if (!settings.isSet(WsdlSettings.EXCLUDED_TYPES)) {
StringList list = new StringList();
list.add("schema@http://www.w3.org/2001/XMLSchema");
settings.setString(WsdlSettings.EXCLUDED_TYPES, list.toXml());
}
if (settings.getString(HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1).equals(
HttpSettings.HTTP_VERSION_0_9)) {
settings.setString(HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1);
}
setIfNotSet(WsdlSettings.NAME_WITH_BINDING, true);
setIfNotSet(WsdlSettings.NAME_WITH_BINDING, 500);
setIfNotSet(HttpSettings.HTTP_VERSION, HttpSettings.HTTP_VERSION_1_1);
setIfNotSet(HttpSettings.MAX_TOTAL_CONNECTIONS, 2000);
setIfNotSet(HttpSettings.RESPONSE_COMPRESSION, true);
setIfNotSet(HttpSettings.LEAVE_MOCKENGINE, true);
setIfNotSet(UISettings.AUTO_SAVE_PROJECTS_ON_EXIT, true);
setIfNotSet(UISettings.SHOW_DESCRIPTIONS, true);
setIfNotSet(WsdlSettings.XML_GENERATION_ALWAYS_INCLUDE_OPTIONAL_ELEMENTS, true);
setIfNotSet(WsaSettings.USE_DEFAULT_RELATES_TO, true);
setIfNotSet(WsaSettings.USE_DEFAULT_RELATIONSHIP_TYPE, true);
setIfNotSet(UISettings.SHOW_STARTUP_PAGE, true);
setIfNotSet(UISettings.GC_INTERVAL, "60");
setIfNotSet(WsdlSettings.CACHE_WSDLS, true);
setIfNotSet(WsdlSettings.PRETTY_PRINT_RESPONSE_MESSAGES, true);
setIfNotSet(HttpSettings.RESPONSE_COMPRESSION, true);
setIfNotSet(HttpSettings.INCLUDE_REQUEST_IN_TIME_TAKEN, true);
setIfNotSet(HttpSettings.INCLUDE_RESPONSE_IN_TIME_TAKEN, true);
setIfNotSet(HttpSettings.LEAVE_MOCKENGINE, true);
setIfNotSet(HttpSettings.START_MOCK_SERVICE, true);
setIfNotSet(UISettings.AUTO_SAVE_INTERVAL, "0");
setIfNotSet(UISettings.GC_INTERVAL, "60");
setIfNotSet(UISettings.SHOW_STARTUP_PAGE, true);
setIfNotSet(WsaSettings.SOAP_ACTION_OVERRIDES_WSA_ACTION, false);
setIfNotSet(WsaSettings.USE_DEFAULT_RELATIONSHIP_TYPE, true);
setIfNotSet(WsaSettings.USE_DEFAULT_RELATES_TO, true);
setIfNotSet(WsaSettings.OVERRIDE_EXISTING_HEADERS, false);
setIfNotSet(WsaSettings.ENABLE_FOR_OPTIONAL, false);
setIfNotSet(VersionUpdateSettings.AUTO_CHECK_VERSION_UPDATE, true);
if (!settings.isSet(ProxySettings.AUTO_PROXY) && !settings.isSet(ProxySettings.ENABLE_PROXY)) {
settings.setBoolean(ProxySettings.AUTO_PROXY, true);
settings.setBoolean(ProxySettings.ENABLE_PROXY, true);
}
boolean setWsiDir = false;
String wsiLocationString = settings.getString(WSISettings.WSI_LOCATION, null);
if (StringUtils.isNullOrEmpty(wsiLocationString)) {
setWsiDir = true;
} else {
File wsiFile = new File(wsiLocationString);
if (!wsiFile.exists()) {
setWsiDir = true;
}
}
if (setWsiDir) {
String wsiDir = System.getProperty("wsi.dir", new File(".").getAbsolutePath());
settings.setString(WSISettings.WSI_LOCATION, wsiDir);
}
HttpClientSupport.addSSLListener(settings);
return settings;
}
private void setIfNotSet(String id, boolean value) {
if (!settings.isSet(id)) {
settings.setBoolean(id, true);
}
}
private void setIfNotSet(String id, String value) {
if (!settings.isSet(id)) {
settings.setString(id, value);
}
}
private void setIfNotSet(String id, long value) {
if (!settings.isSet(id)) {
settings.setLong(id, value);
}
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#importSettings(java.io.File)
*/
public Settings importSettings(File file) throws Exception {
if (file != null) {
log.info("Importing preferences from [" + file.getAbsolutePath() + "]");
return initSettings(file.getAbsolutePath());
}
return null;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#getSettings()
*/
public Settings getSettings() {
if (settings == null) {
initSettings(DEFAULT_SETTINGS_FILE);
}
return settings;
}
protected void initDefaultSettings(Settings settings2) {
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#saveSettings()
*/
public String saveSettings() throws Exception {
PropertyExpansionUtils.saveGlobalProperties();
SecurityScanUtil.saveGlobalSecuritySettings();
isSavingSettings = true;
try {
if (settingsFile == null) {
settingsFile = getRoot() + File.separatorChar + DEFAULT_SETTINGS_FILE;
}
// Save settings to root or user.home
File file = new File(settingsFile);
if (!file.canWrite()) {
file = new File(new File(System.getProperty("user.home", ".")), DEFAULT_SETTINGS_FILE);
}
SoapuiSettingsDocumentConfig settingsDocument = (SoapuiSettingsDocumentConfig) this.settingsDocument.copy();
String password = settings.getString(SecuritySettings.SHADOW_PASSWORD, null);
if (password != null && password.length() > 0) {
try {
byte[] data = settingsDocument.xmlText().getBytes();
String encryptionAlgorithm = "des3";
byte[] encryptedData = OpenSSL.encrypt(encryptionAlgorithm, password.toCharArray(), data);
settingsDocument.setSoapuiSettings(null);
settingsDocument.getSoapuiSettings().setEncryptedContent(encryptedData);
settingsDocument.getSoapuiSettings().setEncryptedContentAlgorithm(encryptionAlgorithm);
} catch (UnsupportedEncodingException e) {
log.error("Encryption error", e);
} catch (IOException e) {
log.error("Encryption error", e);
} catch (GeneralSecurityException e) {
log.error("Encryption error", e);
}
}
FileOutputStream out = new FileOutputStream(file);
settingsDocument.save(out);
out.flush();
out.close();
log.info("Settings saved to [" + file.getAbsolutePath() + "]");
lastSettingsLoad = file.lastModified();
return file.getAbsolutePath();
} finally {
isSavingSettings = false;
}
}
public String getSettingsFile() {
return settingsFile;
}
public void setSettingsFile(String settingsFile) {
this.settingsFile = settingsFile;
}
protected void initLog() {
if (!logIsInitialized) {
String logFileName = System.getProperty(SoapUISystemProperties.SOAPUI_LOG4j_CONFIG_FILE, "soapui-log4j.xml");
File log4jconfig = root == null ? new File(logFileName) : new File(new File(getRoot()), logFileName);
if (log4jconfig.exists()) {
System.out.println("Configuring log4j from [" + log4jconfig.getAbsolutePath() + "]");
DOMConfigurator.configureAndWatch(log4jconfig.getAbsolutePath(), 5000);
} else {
URL url = SoapUI.class.getResource("/com/eviware/soapui/resources/conf/soapui-log4j.xml");
if (url != null) {
DOMConfigurator.configure(url);
} else {
System.err.println("Missing soapui-log4j.xml configuration");
}
}
logIsInitialized = true;
log = Logger.getLogger(DefaultSoapUICore.class);
}
}
public synchronized void loadExternalLibraries() {
if (extClassLoader == null) {
try {
extClassLoader = SoapUIExtensionClassLoader.create(getRoot(), getExtensionClassLoaderParent());
} catch (MalformedURLException e) {
SoapUI.logError(e);
}
}
}
protected ClassLoader getExtensionClassLoaderParent() {
return SoapUI.class.getClassLoader();
}
public SoapUIExtensionClassLoader getExtensionClassLoader() {
if (extClassLoader == null) {
loadExternalLibraries();
}
return extClassLoader;
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#getMockEngine()
*/
public MockEngine getMockEngine() {
if (mockEngine == null) {
synchronized (DefaultSoapUICore.class) {
if (mockEngine == null) {
mockEngine = buildMockEngine();
}
}
}
return mockEngine;
}
protected MockEngine buildMockEngine() {
return new JettyMockEngine();
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#getListenerRegistry()
*/
public SoapUIListenerRegistry getListenerRegistry() {
if (listenerRegistry == null) {
initListenerRegistry();
}
return listenerRegistry;
}
protected void initListenerRegistry() {
listenerRegistry = new SoapUIListenerRegistry(null);
}
/*
* (non-Javadoc)
*
* @see com.eviware.soapui.SoapUICore#getActionRegistry()
*/
public SoapUIActionRegistry getActionRegistry() {
if (actionRegistry == null) {
actionRegistry = initActionRegistry();
}
return actionRegistry;
}
protected SoapUIActionRegistry initActionRegistry() {
return new SoapUIActionRegistry(
DefaultSoapUICore.class.getResourceAsStream("/com/eviware/soapui/resources/conf/soapui-actions.xml"));
}
protected void addExternalListeners(String folder, ClassLoader classLoader) {
File[] actionFiles = new File(folder).listFiles();
if (actionFiles != null) {
for (File actionFile : actionFiles) {
if (actionFile.isDirectory()) {
addExternalListeners(actionFile.getAbsolutePath(), classLoader);
continue;
}
if (!actionFile.getName().toLowerCase().endsWith("-listeners.xml")) {
continue;
}
try {
log.info("Adding listeners from [" + actionFile.getAbsolutePath() + "]");
SoapUI.getListenerRegistry().addConfig(new FileInputStream(actionFile), classLoader);
// We break the general rule that you shouldn't catch Throwable, because we don't want extensions to crash SoapUI
} catch (Throwable e) {
SoapUI.logError(e, "Couldn't load listeners in " + actionFile.getAbsolutePath());
}
}
}
}
protected void addExternalFactories(String folder, ClassLoader classLoader) {
File[] factoryFiles = new File(folder).listFiles();
if (factoryFiles != null) {
for (File factoryFile : factoryFiles) {
if (factoryFile.isDirectory()) {
addExternalListeners(factoryFile.getAbsolutePath(), classLoader);
continue;
}
if (!factoryFile.getName().toLowerCase().endsWith("-factories.xml")) {
continue;
}
try {
log.info("Adding factories from [" + factoryFile.getAbsolutePath() + "]");
getFactoryRegistry().addConfig(new FileInputStream(factoryFile), classLoader);
// We break the general rule that you shouldn't catch Throwable, because we don't want extensions to crash SoapUI
} catch (Throwable e) {
SoapUI.logError(e, "Couldn't load factories in " + factoryFile.getAbsolutePath());
}
}
}
}
public static boolean settingsFileExists() {
DefaultSoapUICore soapUICore = new DefaultSoapUICore();
return new File(DEFAULT_SETTINGS_FILE).exists() ||
new File(new File(soapUICore.getRoot()), DEFAULT_SETTINGS_FILE).exists() ||
new File(System.getProperty("user.home", ".") + File.separator + DEFAULT_SETTINGS_FILE).exists();
}
private class SettingsWatcher extends TimerTask {
@Override
public void run() {
if (settingsFile != null && !isSavingSettings) {
File file = new File(settingsFile);
if (file.exists() && file.lastModified() > lastSettingsLoad) {
log.info("Reloading updated settings file");
initSettings(settingsFile);
SoapUI.updateProxyFromSettings();
}
}
}
}
@Override
public SoapUIFactoryRegistry getFactoryRegistry() {
if (factoryRegistry == null) {
initFactoryRegistry();
}
return factoryRegistry;
}
protected void initFactoryRegistry() {
factoryRegistry = new SoapUIFactoryRegistry(null);
}
protected void initSecurityScanRegistry() {
securityScanRegistry = SecurityScanRegistry.getInstance();
}
@Override
public SecurityScanRegistry getSecurityScanRegistry() {
if (securityScanRegistry == null) {
initSecurityScanRegistry();
}
return securityScanRegistry;
}
}