/*******************************************************************************
* Copyright (c) 2012 - 2016 Pivotal Software, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal Software, Inc. - initial API and implementation
*******************************************************************************/
package com.vmware.vfabric.ide.eclipse.tcserver.internal.core;
import java.net.URL;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jst.server.tomcat.core.internal.ITomcatServer;
import org.eclipse.jst.server.tomcat.core.internal.Messages;
import org.eclipse.jst.server.tomcat.core.internal.TomcatPlugin;
import org.eclipse.jst.server.tomcat.core.internal.TomcatServer;
import org.eclipse.jst.server.tomcat.core.internal.Trace;
import org.eclipse.osgi.util.NLS;
import org.eclipse.wst.server.core.IModule;
import org.eclipse.wst.server.core.IRuntime;
import org.eclipse.wst.server.core.ServerPort;
import org.eclipse.wst.server.core.ServerUtil;
/**
* @author Steffen Pingel
* @author Christian Dupuis
* @author Leo Dos Santos
* @author Tomasz Zarna
*/
public class TcServer extends TomcatServer {
public static String ID_TC_SERVER_2_5 = "com.vmware.server.tc.70";
public static String ID_TC_SERVER_3_0 = "com.pivotal.server.tc.80";
public static final String DEFAULT_DEPLOYER_HOST = "localhost";
public static final String DEFAULT_DEPLOYER_SERVICE = "Catalina";
/**
* Default filename patters that should to avoid a webapp reload when
* publishing.
*/
public static final String DEFAULT_STATIC_FILENAMES = "*.html,*.xhtml,*.css,*.jspx,*.js,*.jsp,*.gif,*.jpg,*.png,*.swf,*-flow.xml,*.properties,*.xml,!tiles.xml,!web.xml";
/** Boolean property that determines if the ASF layout should be used. */
public static final String KEY_ASF_LAYOUT = "com.springsource.tcserver.asf";
/**
* String property for the server instance for combined or separate layout.
*/
public static final String KEY_SERVER_NAME = "com.springsource.tcserver.name";
public static final String PROPERTY_ADD_EXTRA_VMARGS = "addExtraVmArgs";
public static final String PROPERTY_AGENT_OPTIONS = "com.springsource.tcserver.agent.options";
public static final String PROPERTY_AGENT_REDEPLOY = "com.springsource.tcserver.agent.deploy";
public static final String PROPERTY_DEPLOYER_HOST = "modifyDeployerHost";
public static final String PROPERTY_DEPLOYER_SERVICE = "modifyDeployerService";
/**
* Property key for a boolean that indicates managing of webapp reloading is
* enabled.
*/
public static final String PROPERTY_ENHANCED_REDEPLOY = "com.springsource.tcserver.jmx.deploy";
public static final String PROPERTY_JMX_PASSWORD = "modifyJmxPassowrd";
public static final String PROPERTY_JMX_PORT = "modifyJmxPort";
public static final String PROPERTY_JMX_USER = "modifyJmxUser";
public static final String PROPERTY_REMOVE_EXTRA_VMARGS = "removeExtraVmArgs";
/**
* Property key for list of patterns to avoid a webapp reload when
* publishing.
*/
public static final String PROPERTY_STATIC_FILENAMES = "com.springsource.tcserver.filenames.static";
private static TcServerCallback callback;
private static final String DEFAULT_JMX_PORT = "6969";
@SuppressWarnings("unchecked")
public List<String> getAddExtraVmArgs() {
return getAttribute(PROPERTY_ADD_EXTRA_VMARGS, Collections.EMPTY_LIST);
}
public String getAgentOptions() {
return getAttribute(PROPERTY_AGENT_OPTIONS, "");
}
public String getDeployerHost() {
return getAttribute(PROPERTY_DEPLOYER_HOST, DEFAULT_DEPLOYER_HOST);
}
public String getDeployerProperty(String key) {
if (PROPERTY_JMX_PORT.equals(key)) {
return getJmxPort();
}
if (PROPERTY_DEPLOYER_HOST.equals(key)) {
return getDeployerHost();
}
if (PROPERTY_DEPLOYER_SERVICE.equals(key)) {
return getDeployerService();
}
return getAttribute(key, (String) null);
}
public String getDeployerService() {
return getAttribute(PROPERTY_DEPLOYER_SERVICE, DEFAULT_DEPLOYER_SERVICE);
}
/**
* The runtime may specifies the top-level tc Server directory and not the
* catalina home. This methods returns the actual catalina home this server
* is configured to use.
*/
public IPath getInstanceBase(IRuntime runtime) {
IPath path = runtime.getLocation();
if (isAsfLayout()) {
return getTomcatRuntime().getTomcatLocation();
}
else {
String instanceDir = getInstanceDirectory();
if (instanceDir != null) {
path = Path.fromOSString(instanceDir);
}
String serverName = getAttribute(KEY_SERVER_NAME, (String) null);
if (serverName != null && !path.toOSString().endsWith(serverName)) {
path = path.append(serverName);
}
return path;
}
}
public String getJmxPassword() {
return getAttribute(PROPERTY_JMX_PASSWORD, "");
}
public String getJmxPort() {
return getAttribute(PROPERTY_JMX_PORT, DEFAULT_JMX_PORT);
}
public String getJmxUser() {
return getAttribute(PROPERTY_JMX_USER, "");
}
public Layout getLayout() {
if (isAsfLayout()) {
return Layout.ASF;
}
else {
IPath path = getInstanceBase(getServer().getRuntime());
if (path.append("lib").append("catalina.jar").toFile().exists()) {
return Layout.COMBINED;
}
else {
return Layout.SEPARATE;
}
}
}
@SuppressWarnings("unchecked")
public List<String> getRemoveExtraVmArgs() {
return getAttribute(PROPERTY_REMOVE_EXTRA_VMARGS, Collections.EMPTY_LIST);
}
public String getServerName() {
return getAttribute(TcServer.KEY_SERVER_NAME, (String) null);
}
public String getStaticFilenamePatterns() {
return getAttribute(PROPERTY_STATIC_FILENAMES, DEFAULT_STATIC_FILENAMES);
}
@Override
public TcServerConfiguration getTomcatConfiguration() throws CoreException {
if (configuration == null) {
IFolder folder = getFolder();
configuration = new TcServerConfiguration(this, folder, getTomcatRuntime().supportsServlet30());
try {
((TcServerConfiguration) configuration).load(folder, null);
}
catch (CoreException ce) {
// ignore
configuration = null;
throw ce;
}
}
return (TcServerConfiguration) configuration;
}
@Override
public TcServerRuntime getTomcatRuntime() {
return (TcServerRuntime) super.getTomcatRuntime();
}
@Override
public void importRuntimeConfiguration(IRuntime runtime, IProgressMonitor monitor) throws CoreException {
try {
importRuntimeConfigurationChecked(runtime, monitor);
}
catch (CoreException ce) {
// ignore, need additional configuration for server instance
// Webtools invokes importRuntimeConfiguration() before any
// configuration has taken place therefore this method need to fail
// silently and the configuration needs to be imported again later
// on
configuration = null;
}
}
public void importRuntimeConfigurationChecked(IRuntime runtime, IProgressMonitor monitor) throws CoreException {
if (runtime == null) {
configuration = null;
return;
}
IPath path = getInstanceBase(runtime);
path = path.append("conf");
IFolder folder = getServer().getServerConfiguration();
configuration = new TcServerConfiguration(this, folder);
configuration.importFromPath(path, isTestEnvironment(), monitor);
}
public boolean isAgentRedeployEnabled() {
return getAttribute(PROPERTY_AGENT_REDEPLOY, false);
}
public boolean isAsfLayout() {
return getAttribute(TcServer.KEY_ASF_LAYOUT, true);
}
public boolean isEnhancedRedeployEnabled() {
return getAttribute(PROPERTY_ENHANCED_REDEPLOY, false);
}
public void setAddExtraVmArgs(List<String> value) {
setAttribute(PROPERTY_ADD_EXTRA_VMARGS, value);
}
public void setAgentOptions(String agentOptions) {
setAttribute(PROPERTY_AGENT_OPTIONS, agentOptions);
}
public void setAgentRedeployEnabled(boolean enable) {
setAttribute(PROPERTY_AGENT_REDEPLOY, enable);
}
@Override
public void setDefaults(IProgressMonitor monitor) {
super.setDefaults(monitor);
TcServerUtil.setTcServerDefaultName(getServerWorkingCopy());
// test mode is now supported
// setAttribute(ITomcatServer.PROPERTY_INSTANCE_DIR, (String) null);
// setAttribute(ITomcatServer.PROPERTY_TEST_ENVIRONMENT, false);
// ASF layout is only supported by tc Server 2.0 and earlier
if (isVersion25(getServer().getRuntime()) || isVersion30(getServer().getRuntime())) {
setAttribute(TcServer.KEY_ASF_LAYOUT, false);
setAttribute(ITomcatServer.PROPERTY_SAVE_SEPARATE_CONTEXT_FILES, true);
}
else {
setAttribute(TcServer.KEY_ASF_LAYOUT, true);
}
setTestEnvironment(false);
getCallback().setDefaults(this, monitor);
}
public void setDeployerHost(String value) {
setAttribute(PROPERTY_DEPLOYER_HOST, value);
}
public void setDeployerProperty(String key, String value) {
setAttribute(key, value);
}
public void setDeployerService(String value) {
setAttribute(PROPERTY_DEPLOYER_SERVICE, value);
}
public void setEnhancedRedeployEnabled(boolean enable) {
setAttribute(PROPERTY_ENHANCED_REDEPLOY, enable);
}
public void setJmxPassword(String value) {
setAttribute(PROPERTY_JMX_PASSWORD, value);
}
public void setJmxPort(String value) {
setAttribute(PROPERTY_JMX_PORT, value);
}
public void setJmxUser(String value) {
setAttribute(PROPERTY_JMX_USER, value);
}
public void setRemoveExtraVmArgs(List<String> value) {
setAttribute(PROPERTY_REMOVE_EXTRA_VMARGS, value);
}
public void setStaticFilenamePatterns(String filenamePatterns) {
setAttribute(PROPERTY_STATIC_FILENAMES, filenamePatterns);
}
protected IFolder getFolder() throws CoreException {
IFolder folder = getServer().getServerConfiguration();
if (folder == null || !folder.exists()) {
String path = null;
if (folder != null) {
path = folder.getFullPath().toOSString();
}
throw new CoreException(new Status(IStatus.ERROR, TomcatPlugin.PLUGIN_ID, 0, NLS.bind(
Messages.errorNoConfiguration, path), null));
}
return folder;
}
@Override
protected void initialize() {
super.initialize();
}
public static synchronized TcServerCallback getCallback() {
if (callback == null) {
callback = ExtensionPointReader.readExtension();
if (callback == null) {
// create null callback
callback = new TcServerCallback() {
// ignore
};
}
}
return callback;
}
public static boolean isVersion25(IRuntime runtime) {
return runtime.getRuntimeType().getId().endsWith("70");
}
public static boolean isVersion30(IRuntime runtime) {
return runtime.getRuntimeType().getId().endsWith("80");
}
public static String substitute(String value, Properties properties) {
String[] segments = value.split("\\$\\{");
StringBuffer sb = new StringBuffer(value.length());
sb.append(segments[0]);
for (int i = 1; i < segments.length; i++) {
String segment = segments[i];
String substitution = null;
int brace = segment.indexOf('}');
if (brace > 0) {
String keyword = segment.substring(0, brace);
substitution = properties.getProperty(keyword);
}
if (substitution != null) {
sb.append(substitution);
sb.append(segment.substring(brace + 1));
}
else {
sb.append("${");
sb.append(segment);
}
}
return sb.toString();
}
public enum Layout {
/**
* Uses runtime directory. Does not have an instance directory.
* Supported by v2.0 and earlier only.
*/
ASF,
/** Uses instance directory. Supported by v2.5 and later only. */
COMBINED,
/** Uses runtime and instance directory. Supported by all versions. */
SEPARATE;
public String toString() {
switch (this) {
case ASF:
return "ASF Layout";
case COMBINED:
return "Combined Layout";
case SEPARATE:
return "Separate Layout";
}
throw new IllegalStateException();
};
}
private static class ExtensionPointReader {
private static final String ELEMENT_CALLBACK = "callback";
private static final String ELEMENT_CLASS = "class";
private static final String EXTENSION_ID_CALLBACK = "com.springsource.sts.server.tc.core.callback";
public static TcServerCallback readExtension() {
IExtensionRegistry registry = Platform.getExtensionRegistry();
IExtensionPoint extensionPoint = registry.getExtensionPoint(EXTENSION_ID_CALLBACK);
IExtension[] extensions = extensionPoint.getExtensions();
for (IExtension extension : extensions) {
IConfigurationElement[] elements = extension.getConfigurationElements();
for (IConfigurationElement element : elements) {
if (element.getName().compareTo(ELEMENT_CALLBACK) == 0) {
return readCallbackExtension(element);
}
}
}
return null;
}
private static TcServerCallback readCallbackExtension(IConfigurationElement configurationElement) {
try {
Object object = configurationElement.createExecutableExtension(ELEMENT_CLASS);
if (!(object instanceof TcServerCallback)) {
TomcatPlugin.log(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID, "Could not load "
+ object.getClass().getCanonicalName() + " must implement "
+ TcServerCallback.class.getCanonicalName()));
return null;
}
return (TcServerCallback) object;
}
catch (CoreException e) {
TomcatPlugin.log(new Status(IStatus.ERROR, ITcServerConstants.PLUGIN_ID,
"Could not load callback extension", e));
}
return null;
}
}
@Override
public URL getModuleRootURL(IModule module) {
URL url = super.getModuleRootURL(module);
if (url != null) {
return url;
}
// if standard method fails, return URL for SSL connection
try {
if (module == null) {
return null;
}
TcServerConfiguration config = getTomcatConfiguration();
if (config == null) {
return null;
}
ServerPort sslPort = config.getMainSslPort();
if (sslPort == null) {
return null;
}
int port = sslPort.getPort();
String urlString = "https://" + getServer().getHost();
port = ServerUtil.getMonitoredPort(getServer(), port, "web");
if (port != 443) {
urlString += ":" + port;
}
urlString += config.getWebModuleURL(module);
if (!urlString.endsWith("/")) {
urlString += "/";
}
return new URL(urlString);
}
catch (Exception e) {
Trace.trace(Trace.SEVERE, "Could not get root URL", e);
return null;
}
}
}