Thursday, March 6, 2008

Native libraries with the EclipseTotale Tomcat Plugin

I am a happy user of the EclipseTotale Tomcat Plugin: It is so much faster, more lightweight and convenient and generally easier to use than the server stuff of Eclipse WTP. (Of course, it cannot run JBoss, but I don't expect that it does. :-) It is one of the tools that I use every day.

Unfortunately, I am also one of the poor souls who are forced to work with native libraries. (In my case the authentication libraries of CentraSite.) Native libraries are generally a pain and one of the devils more successful inventions. In the case of the Tomcat plugin they have prevented me from using it for quite some time. Instead I was typically starting Tomcat from a shell script: The shell script has been setting the necessary environment variables like PATH under Windows or LD_LIBRARY_PATH under Linux/Unix, which indicate the location of shared libraries aka DLL's.

I wondered for some time, whether it wouldn't be quite easy to add support for setting these variables to the plugin. At some point, I contacted the plugins author and asked for the sources in order to add the missing feature myself. He never responded. However, recently I found that he did something much better: If you open the plugins zip file, then you'll notice, that it contains a file called tomcatsrc.zip. Yes, these are the plugins sources. And, even better, there also is a file called license.txt, which tells you that the plugin is licensed under the MIT license, a very liberal license, that allows me to change the sources. I could even distribute an updated plugin.

It turned out, that the work was even quite easy. Adding a control to the preferences page, some resource strings and a piece of configuration to an Eclipse configuration object for launching external programs, that's basically it.

If you're interested, I'll post the patch below. Let's hope, that this patch, which I have submitted to the plugins author will appear in the next version.


diff -ubr --exclude='*.class' ./src/com/sysdeo/eclipse/tomcat/editors/ListFieldEditor.java /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/com/sysdeo/eclipse/tomcat/editors/ListFieldEditor.java
--- ./src/com/sysdeo/eclipse/tomcat/editors/ListFieldEditor.java 2005-04-11 12:04:10.000000000 +0200
+++ /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/com/sysdeo/eclipse/tomcat/editors/ListFieldEditor.java 2008-03-06 21:14:19.000000000 +0100
@@ -6,9 +6,9 @@
import java.util.StringTokenizer;



import org.eclipse.jface.dialogs.IDialogConstants;

+import org.eclipse.jface.dialogs.IInputValidator;

import org.eclipse.jface.dialogs.InputDialog;

import org.eclipse.jface.preference.ListEditor;

-import org.eclipse.jface.util.Assert;

import org.eclipse.swt.SWT;

import org.eclipse.swt.events.DisposeEvent;

import org.eclipse.swt.events.DisposeListener;

@@ -55,10 +55,13 @@
*/

protected SelectionListener selectionListener;



+ private final IInputValidator validator;

+

/**

* Creates a new list field editor

*/

public ListFieldEditor() {

+ validator = null;

}



/**

@@ -70,10 +73,13 @@
* the label text of the field editor

* @param parent

* the parent of the field editor's control

+ * @param validator

+ * A validator for validating the users input

*/

- public ListFieldEditor(String name, String labelText, Composite parent) {

+ public ListFieldEditor(String name, String labelText, Composite parent, IInputValidator validator) {

init(name, labelText);

createControl(parent);

+ this.validator = validator;

}



/**

@@ -440,7 +446,7 @@
defaultValue = list.getSelection()[0];

}



- InputDialog dialog = new InputDialog(getShell(), "New Tomcat JVM paramater", "Enter a JVM parameter", defaultValue, null);

+ InputDialog dialog = new InputDialog(getShell(), "New Tomcat JVM paramater", "Enter a JVM parameter", defaultValue, validator);

String param = null;

int dialogCode = dialog.open();

if (dialogCode == InputDialog.OK) {

diff -ubr --exclude='*.class' ./src/com/sysdeo/eclipse/tomcat/TomcatBootstrap.java /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/com/sysdeo/eclipse/tomcat/TomcatBootstrap.java
--- ./src/com/sysdeo/eclipse/tomcat/TomcatBootstrap.java 2007-03-28 20:58:58.000000000 +0200
+++ /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/com/sysdeo/eclipse/tomcat/TomcatBootstrap.java 2008-03-06 20:49:44.000000000 +0100
@@ -11,8 +11,10 @@
import java.io.PrintWriter;

import java.util.ArrayList;

import java.util.Collection;

+import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

+import java.util.Map;



import org.eclipse.core.resources.IFile;

import org.eclipse.core.resources.IProject;

@@ -198,14 +200,16 @@
jvmArguments.append(" " + vmArgs[i]);

}



+ Map envVariables = getEnvVariables();

+

if(action == RUN) {

- VMLauncherUtility.runVM(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger, saveConfig);

+ VMLauncherUtility.runVM(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger, saveConfig, envVariables);

}

if(action == LOG) {

- VMLauncherUtility.log(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger);

+ VMLauncherUtility.log(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger, envVariables);

}

if(action == ADD_LAUNCH) {

- VMLauncherUtility.createConfig(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger, true);

+ VMLauncherUtility.createConfig(getLabel(), getMainClass(), classpath, bootClasspath, jvmArguments.toString(), programArguments.toString(), isDebugMode(), showInDebugger, true, envVariables);

}



}

@@ -375,4 +379,17 @@
return StringUtil.concatUniq(previous, prefBootClasspath);

}



+ private Map getEnvVariables() {

+ final String[] envVariables = StringUtil.cutString(TomcatLauncherPlugin.getDefault().getEnvVariables(), TomcatPluginResources.PREF_PAGE_LIST_SEPARATOR);

+ final Map result = new HashMap();

+ if (envVariables != null) {

+ for (int i = 0; i < envvariable =" envVariables[i];" key =" TomcatLauncherPlugin.getEnvVariableKey(envVariable);" value =" TomcatLauncherPlugin.getEnvVariableValue(envVariable);" exclude="'*.class'" field_width =" 50;" jvmparamaters =" new" jvmparamaters =" new" jvmclasspath =" new" jvmbootclasspath =" new" envvariables =" new" exclude="'*.class'" tomcat_pref_jvm_parameters_key = "jvmParameters" tomcat_pref_jvm_classpath_key = "jvmClasspath" tomcat_pref_jvm_bootclasspath_key = "jvmBootClasspath" tomcat_pref_env_variables_key = "envVariables" tomcat_pref_projectsincp_key = "projectsInCp" tomcat_pref_projectsinsourcepath_key = "projectsInSourcePath" tomcat_pref_computesourcepath_key = "computeSourcePath" pref =" TomcatLauncherPlugin.getDefault().getPreferenceStore();" pref =" TomcatLauncherPlugin.getDefault().getPreferenceStore();" offset =" envVariable.indexOf('="');" offset ="="" s =" envVariable.substring(0," offset =" envVariable.indexOf('="');" offset ="="" exclude="'*.class'" pref_page_parameters_label =" TomcatLauncherPlugin.getResourceString(" pref_page_env_variables_label =" +" pref_page_env_variable_invalid_msg =" +" pref_page_dump_config_label =" TomcatLauncherPlugin.getResourceString(" exclude="'*.class'" vminstall =" getVMInstall();" mode =" ILaunchManager.RUN_MODE;" vmrunner =" vmInstall.getVMRunner(mode);" config =" createConfig(label," config =" createConfig(label," sourcelocator =" getSourceLocator(config," trace =" new"> Label : " + label);

trace.append("\n-> ClassToLaunch : " + classToLaunch);

@@ -138,7 +140,7 @@
TomcatLauncherPlugin.log(trace.toString());



try {

- ILaunchConfigurationWorkingCopy config = createConfig(label, classToLaunch, classpath, bootClasspath, vmArgs, prgArgs, debug, showInDebugger, false);

+ ILaunchConfigurationWorkingCopy config = createConfig(label, classToLaunch, classpath, bootClasspath, vmArgs, prgArgs, debug, showInDebugger, false, envVariables);

getSourceLocator(config, true);

} catch (CoreException e) {

TomcatLauncherPlugin.log("getSourceLocator failed");

@@ -148,7 +150,7 @@
}





- static public ILaunchConfigurationWorkingCopy createConfig(String label, String classToLaunch, String[] classpath, String[] bootClasspath, String vmArgs, String prgArgs, boolean debug, boolean showInDebugger, boolean saveConfig) throws CoreException {

+ static public ILaunchConfigurationWorkingCopy createConfig(String label, String classToLaunch, String[] classpath, String[] bootClasspath, String vmArgs, String prgArgs, boolean debug, boolean showInDebugger, boolean saveConfig, Map envVariables) throws CoreException {

IVMInstall vmInstall = getVMInstall();



ILaunchConfigurationType launchType = DebugPlugin.getDefault().getLaunchManager().getLaunchConfigurationType("org.eclipse.jdt.launching.localJavaApplication");

@@ -218,6 +220,8 @@
}

config.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, catalinaBase);



+ config.setAttribute(LaunchManager.ATTR_ENVIRONMENT_VARIABLES, envVariables);

+

if(saveConfig) {

getSourceLocator(config, false);

config.doSave();

diff -ubr --exclude='*.class' ./src/resources_de.properties /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/resources_de.properties
--- ./src/resources_de.properties 2004-06-17 19:06:12.000000000 +0200
+++ /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/resources_de.properties 2008-03-06 21:20:48.000000000 +0100
@@ -32,6 +32,8 @@
pref.page.unselectAll.label=Alles abw\u00E4hlen

pref.page.jvmSettings.label=Setzen Sie die folgenden Felder nur im Falle der bestimmten Anforderungen

pref.page.parameters.label=Zu JVM Parametern hinzuf\u00FCgen

+pref.page.env.variables.label=Umgebungsvariablen

+pref.page.env.variable.invalid.msg=Eine Umgebungsvariable muss in der Form NAME=WERT angegeben werden.

pref.page.bootclasspath.label=Boot Classpath

pref.page.classpath.label=Classpath (Vor dem erstellten Classpath)

pref.page.chooseversion.label=Tomcat Version

diff -ubr --exclude='*.class' ./src/resources.properties /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/resources.properties
--- ./src/resources.properties 2006-10-23 22:01:18.000000000 +0200
+++ /home/jwi/workspace/com.sysdeo.eclipse.tomcat/src/resources.properties 2008-03-06 21:19:57.000000000 +0100
@@ -35,6 +35,8 @@
pref.page.unselectAll.label = Unselect All

pref.page.jvmSettings.label = Set following fields only if you have particular requirements

pref.page.parameters.label = Append to JVM Parameters

+pref.page.env.variables.label = Environment variables

+pref.page.env.variable.invalid.msg = An environment variable must be specified in the form NAME=VALUE.

pref.page.jre.label = JRE

pref.page.bootclasspath.label = Boot Classpath (rt.jar required)

pref.page.classpath.label = Classpath (Before generated classpath)