[99831] external launch support
diff --git a/plugins/org.eclipse.jst.server.generic.core/META-INF/MANIFEST.MF b/plugins/org.eclipse.jst.server.generic.core/META-INF/MANIFEST.MF
index 337f7bd..6623452 100644
--- a/plugins/org.eclipse.jst.server.generic.core/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.jst.server.generic.core/META-INF/MANIFEST.MF
@@ -27,5 +27,6 @@
  org.eclipse.emf.common;visibility:=reexport,
  org.eclipse.emf.ecore,
  org.eclipse.emf.ecore.xmi,
- org.eclipse.ui.externaltools
+ org.eclipse.ui.externaltools,
+ org.apache.ant
 Eclipse-AutoStart: true
diff --git a/plugins/org.eclipse.jst.server.generic.core/plugin.properties b/plugins/org.eclipse.jst.server.generic.core/plugin.properties
index af10154..620d134 100644
--- a/plugins/org.eclipse.jst.server.generic.core/plugin.properties
+++ b/plugins/org.eclipse.jst.server.generic.core/plugin.properties
@@ -2,8 +2,9 @@
 providerName=Eclipse.org
 pluginDescription=Provides generic server tools with easy to develop meta data configuration files
 
+externalLaunchConfigurationTypeName=Generic Server
 launchConfigurationTypeName=Generic Server
 extensionPointServerdefinition=Server definition
 extensionPointGenericpublisher=Generic Publisher
 # ====================================================================
-

+
diff --git a/plugins/org.eclipse.jst.server.generic.core/plugin.xml b/plugins/org.eclipse.jst.server.generic.core/plugin.xml
index 95f00e0..4241800 100644
--- a/plugins/org.eclipse.jst.server.generic.core/plugin.xml
+++ b/plugins/org.eclipse.jst.server.generic.core/plugin.xml
@@ -12,7 +12,7 @@
         class="org.eclipse.jst.server.generic.core.internal.GenericServerRuntimeTargetHandler"/>
 	</extension>
 
-   <extension point="org.eclipse.debug.core.launchConfigurationTypes">
+ <extension point="org.eclipse.debug.core.launchConfigurationTypes">
      <launchConfigurationType
         id="org.eclipse.jst.server.generic.core.launchConfigurationType"
         name="%launchConfigurationTypeName"
@@ -20,22 +20,31 @@
         modes="run, debug"
         sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
         sourcePathComputerId="org.eclipse.jst.server.generic.core.sourcePathComputer"/>
-  </extension>
+     <launchConfigurationType
+        id="org.eclipse.jst.server.generic.core.ExternalLaunchConfigurationType"
+        name="%externalLaunchConfigurationTypeName"
+        delegate="org.eclipse.jst.server.generic.core.internal.ExternalLaunchConfigurationDelegate"
+        modes="run, debug"
+        sourceLocatorId="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"
+        sourcePathComputerId="org.eclipse.jst.server.generic.core.sourcePathComputer"/>
+ </extension>
 
-   <extension point="org.eclipse.debug.core.sourcePathComputers">
+ <extension point="org.eclipse.debug.core.sourcePathComputers">
      <sourcePathComputer
         id="org.eclipse.jst.server.generic.core.sourcePathComputer"
         class="org.eclipse.jst.server.generic.core.internal.GenericServerSourcePathComputerDelegate"/>
-   </extension>
+ </extension>
  
-   <extension point="org.eclipse.wst.server.core.launchableAdapters">
+ <extension point="org.eclipse.wst.server.core.launchableAdapters">
       <launchableAdapter
          class="org.eclipse.jst.server.generic.core.internal.GenericServerLaunchableAdapterDelegate"
          id="org.eclipse.jst.server.generic.web"/>
-   </extension>
-   <extension point="org.eclipse.jst.server.generic.core.genericpublisher">
+ </extension>
+ 
+ <extension point="org.eclipse.jst.server.generic.core.genericpublisher">
       <genericpublisher
             class="org.eclipse.jst.server.generic.core.internal.AntPublisher"
             id="org.eclipse.jst.server.generic.antpublisher"/>
-   </extension>
+ </extension>
+
 </plugin>
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalLaunchConfigurationDelegate.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalLaunchConfigurationDelegate.java
new file mode 100644
index 0000000..5f68472
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalLaunchConfigurationDelegate.java
@@ -0,0 +1,189 @@
+/*******************************************************************************
+ * Copyright (c) 2005 BEA Systems, 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:
+ *    rfrost@bea.com
+ *    tyip@bea.com
+ *    
+ *    Based on GenericServerLaunchConfigurationDelegate by Gorkem Ercan
+ *******************************************************************************/
+
+package org.eclipse.jst.server.generic.core.internal;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tools.ant.taskdefs.Execute;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IProcess;
+import org.eclipse.debug.core.model.RuntimeProcess;
+import org.eclipse.jdt.internal.launching.JavaRemoteApplicationLaunchConfigurationDelegate;
+import org.eclipse.jdt.internal.launching.LaunchingPlugin;
+import org.eclipse.jdt.launching.AbstractJavaLaunchConfigurationDelegate;
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+import org.eclipse.wst.server.core.IServer;
+import org.eclipse.wst.server.core.ServerUtil;
+import org.eclipse.wst.server.core.model.ServerBehaviourDelegate;
+
+/**
+ * <p>Extension of <code>AbstractJavaLaunchConfigurationDelegate</code> that supports 
+ * servers which are started/stopped via external executables (e.g. scripts).</p>
+ * 
+ * <p>Note: <code>AbstractJavaLaunchConfigurationDelegate</code> is extended simply to take advantage
+ * of a set of useful code that is not directly related to launching a JVM-based app.</p>
+ */
+public class ExternalLaunchConfigurationDelegate extends AbstractJavaLaunchConfigurationDelegate {
+
+	/**
+	 * Identifier for the executable server configuration type
+	 * (value <code>"org.eclipse.jst.server.generic.core.ExternalLaunchConfigurationType"</code>).
+	 */
+	public static final String ID_EXTERNAL_LAUNCH_TYPE = CorePlugin.PLUGIN_ID + ".ExternalLaunchConfigurationType"; //$NON-NLS-1$
+
+	/**
+	 * Name of the launch configuration attribute that holds the external executable commandline.
+	 */
+	public static final String COMMANDLINE = LaunchingPlugin.getUniqueIdentifier() + ".COMMANDLINE"; //$NON-NLS-1$
+
+	/**
+	 * Name of the launch configuration attribute that holds a descriptive name for the external executable.
+	 */
+	public static final String EXECUTABLE_NAME = LaunchingPlugin.getUniqueIdentifier() + ".EXECUTABLE_NAME"; //$NON-NLS-1$
+
+	/**
+	 * Name of the launch configuration attribute that holds the debug port.
+	 */
+	public static final String DEBUG_PORT = LaunchingPlugin.getUniqueIdentifier() + ".DEBUG_PORT"; //$NON-NLS-1$
+	
+	/**
+	 * Default value for the descriptive name for the external executable.
+	 */
+	public static final String DEFAULT_EXECUTABLE_NAME = "External Generic Server";
+	
+	/**
+	 * Debugging launch configuration delegate.
+	 */
+	private static JavaRemoteApplicationLaunchConfigurationDelegate debuggingDelegate =
+        new JavaRemoteApplicationLaunchConfigurationDelegate();
+	
+	/* (non-Javadoc)
+	 * @see org.eclipse.debug.core.model.ILaunchConfigurationDelegate#launch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String, org.eclipse.debug.core.ILaunch, org.eclipse.core.runtime.IProgressMonitor)
+	 */
+	public void launch(ILaunchConfiguration configuration, 
+			       String mode,
+			       ILaunch launch, 
+			       IProgressMonitor monitor) throws CoreException {
+		IServer server = ServerUtil.getServer(configuration);
+		if (server == null) {
+		    abort(GenericServerCoreMessages.missingServer, null, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
+		}	
+
+		ExternalServerBehaviour serverBehavior = (ExternalServerBehaviour) server.loadAdapter(ServerBehaviourDelegate.class, null);
+		
+		// initialize the server, check the ports and start the PingThread that will check 
+		// server state
+		serverBehavior.setupLaunch(launch, mode, monitor);
+		
+		// get the executable commandline
+		String commandline = configuration.getAttribute(COMMANDLINE, (String) null);
+		if (commandline == null) {
+			abort(GenericServerCoreMessages.commandlineUnspecified, null, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR);			
+		}
+		
+		// get a descriptive name for the executable
+		String executableName = configuration.getAttribute(EXECUTABLE_NAME, DEFAULT_EXECUTABLE_NAME);
+		
+		// get the executable environment
+		ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
+		String[] env = manager.getEnvironment(configuration);
+		
+		// get the working directory
+		File workingDir = verifyWorkingDirectory(configuration);
+		if (workingDir == null) {
+			abort(GenericServerCoreMessages.workingdirUnspecified, null, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR);			
+		}
+		
+		// Launch the executable for the configuration using the Ant Execute class
+		try {
+			Process process = Execute.launch(null, new String[]{commandline}, env, workingDir, true);
+			IProcess runtimeProcess = new RuntimeProcess(launch, process, executableName, null);
+			launch.addProcess(runtimeProcess);
+			serverBehavior.setProcess(runtimeProcess);
+		} catch (IOException ioe) {
+			abort(GenericServerCoreMessages.errorLaunchingExecutable, ioe,  IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
+		}
+
+		if (mode.equals("debug")) {
+			ILaunchConfigurationWorkingCopy wc = createDebuggingConfig(configuration);
+			// if we're launching the debugging we need to wait for the config to start
+			// before launching the debugging session
+			serverBehavior.setDebuggingConfig(wc, mode, launch, monitor);
+		}
+	}
+
+	private ILaunchConfigurationWorkingCopy createDebuggingConfig(ILaunchConfiguration configuration) 
+	throws CoreException {
+        ILaunchConfigurationWorkingCopy wc = configuration.getWorkingCopy();
+        setDebugArgument(wc, IJavaLaunchConfigurationConstants.ATTR_CONNECT_MAP, "hostname", "localhost");
+        String port = configuration.getAttribute(DEBUG_PORT, (String) null);
+        if (port==null || port.length()==0) {
+        	abort(GenericServerCoreMessages.debugPortUnspecified, null, IJavaLaunchConfigurationConstants.ERR_INTERNAL_ERROR);
+        }
+        setDebugArgument(wc, IJavaLaunchConfigurationConstants.ATTR_CONNECT_MAP, "port", port);
+        setDebugArgument(wc, ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, "debugFlag", "true");		
+        return wc;
+	}
+	
+	/**
+	 * Starts the debugging session
+	 */
+	protected static void startDebugging(ILaunchConfigurationWorkingCopy wc,
+			       						 String mode,
+			       						 ILaunch launch, 
+			       						 IProgressMonitor monitor) throws CoreException {
+		Trace.trace(Trace.FINEST, "Starting debugging");
+		debuggingDelegate.launch(wc, mode, launch, monitor);
+	}
+	
+    private void setDebugArgument(ILaunchConfigurationWorkingCopy config, String attribKey, String key, String arg) {
+        try {
+            Map args = config.getAttribute(attribKey, (Map)null);
+            if (args!=null) {
+                args = new HashMap(args);
+            } else {
+                args = new HashMap();
+            }
+            args.put(key, String.valueOf(arg));
+            config.setAttribute(attribKey, args);
+        } catch (CoreException ce) {
+            // ignore
+        }        
+    }
+	
+	/**
+	 * Throws a core exception with the given message and optional
+	 * exception. The exception's status code will indicate an error.
+	 * 
+	 * @param message error message
+	 * @param exception cause of the error, or <code>null</code>
+	 * @exception CoreException with the given message and underlying
+	 *  exception
+	 */
+	protected void abort(String message, Throwable exception, int code) throws CoreException {
+		throw new CoreException(new Status(IStatus.ERROR, CorePlugin.getDefault().getBundle().getSymbolicName(), code, message, exception));
+	}
+}
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerBehaviour.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerBehaviour.java
new file mode 100644
index 0000000..aebb883
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerBehaviour.java
@@ -0,0 +1,171 @@
+/*******************************************************************************
+ * Copyright (c) 2005 BEA Systems, 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:
+ *    rfrost@bea.com - initial API and implementation
+ *    
+ *    Based on GenericServerBehavior by Gorkem Ercan
+ *******************************************************************************/
+package org.eclipse.jst.server.generic.core.internal;
+
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
+import org.eclipse.jst.server.generic.internal.xml.Resolver;
+import org.eclipse.jst.server.generic.servertype.definition.External;
+import org.eclipse.jst.server.generic.servertype.definition.ServerRuntime;
+import org.eclipse.wst.server.core.IServer;
+import org.eclipse.wst.server.core.internal.Server;
+
+/**
+ * Subclass of <code>GenericServerBehavior</code> that supports 
+ * servers which are started/stopped via external executables (e.g. scripts).
+ */
+public class ExternalServerBehaviour extends GenericServerBehaviour {
+	
+	// config for debugging session
+	private ILaunchConfigurationWorkingCopy wc;
+    private String mode;
+    private ILaunch launch; 
+    private IProgressMonitor monitor;
+	
+	/**
+	 * Override to trigger the launch of the debugging session (if appropriate).
+	 */
+	protected synchronized void setServerStarted() {
+		super.setServerStarted();
+		if (wc != null) {
+			try {
+				ExternalLaunchConfigurationDelegate.startDebugging(wc, mode, launch, monitor);
+			} catch (CoreException ce) {
+				// swallow
+			} finally {
+				clearDebuggingConfig();
+			}
+		}
+ 	}
+	
+	/**
+	 * Since terminate() is called during restart, need to override to
+	 * call shutdown instead of just killing the original process.
+	 */
+	protected void terminate() {
+		int state = getServer().getServerState();
+		if (state == IServer.STATE_STOPPED) 
+    		return;
+    
+		// need to execute a standard shutdown rather than
+		// just killing the original process
+		// the originally launched process may have only been
+		// a proxy and thus no longer executing
+		shutdown(state);
+	}
+	
+	/**
+	 * Override superclass method to correctly setup the launch configuration for starting an external
+	 * server.
+	 */
+	public void setupLaunchConfiguration(ILaunchConfigurationWorkingCopy workingCopy,
+										 IProgressMonitor monitor) throws CoreException {
+		clearDebuggingConfig();
+		ServerRuntime serverDef = getServerDefinition();
+		Resolver resolver = serverDef.getResolver();
+		workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
+					resolver.resolveProperties(serverDef.getStart().getWorkingDirectory()));
+		String external = resolver.resolveProperties(getExternalForOS(serverDef.getStart().getExternal()));
+		workingCopy.setAttribute(ExternalLaunchConfigurationDelegate.COMMANDLINE, external);
+		workingCopy.setAttribute(ExternalLaunchConfigurationDelegate.DEBUG_PORT, 
+					resolver.resolveProperties(serverDef.getStart().getDebugPort()));
+		// just use the commandline for now
+		workingCopy.setAttribute(ExternalLaunchConfigurationDelegate.EXECUTABLE_NAME, external); 
+	}
+
+	/*
+	 * Returns the first external whose "os" attribute matches (case insensitive) the beginning 
+	 * of the name of the current OS (as determined by the System "os.name" property). If
+	 * no such match is found, returns the first external that does not have an OS attribute.
+	 */
+	private String getExternalForOS(List externals) {
+		String currentOS = System.getProperty("os.name").toLowerCase();
+		External external;
+		String matchingExternal = null;
+		String externalOS;
+		Iterator i = externals.iterator();
+		while (i.hasNext()) {
+			external= (External) i.next();
+			externalOS = external.getOs();
+			if (externalOS == null) {
+				if (matchingExternal == null) {
+					matchingExternal = external.getValue();
+				}
+			} else if (currentOS.startsWith(externalOS.toLowerCase())) {
+				matchingExternal = external.getValue();
+				break;
+			}
+		}
+		return matchingExternal;
+	}
+
+	/**
+     * Returns the String ID of the launch configuration type.
+     * @return
+     */
+	protected String getConfigTypeID() {
+		return ExternalLaunchConfigurationDelegate.ID_EXTERNAL_LAUNCH_TYPE;
+	}
+
+	/**
+	 * Returns the String name of the stop launch configuration.
+	 * @return
+	 */
+	protected String getStopLaunchName() {
+		return GenericServerCoreMessages.externalStopLauncher;
+	}
+	
+	/**
+	 * Sets up the launch configuration for stopping the server.
+	 * @param workingCopy
+	 */
+	protected void setupStopLaunchConfiguration(GenericServerRuntime runtime, ILaunchConfigurationWorkingCopy wc) {
+		clearDebuggingConfig();
+		ServerRuntime serverDef = getServerDefinition();
+		Resolver resolver = serverDef.getResolver(); 
+		wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
+					resolver.resolveProperties(serverDef.getStop().getWorkingDirectory()));
+		String external = resolver.resolveProperties(getExternalForOS(serverDef.getStop().getExternal()));
+		wc.setAttribute(ExternalLaunchConfigurationDelegate.COMMANDLINE, external);
+		// just use commandline for now
+		wc.setAttribute(ExternalLaunchConfigurationDelegate.EXECUTABLE_NAME, external); 	
+		wc.setAttribute(Server.ATTR_SERVER_ID, getServer().getId());
+	}
+	
+	/**
+	 * Sets the configuration to use for launching a debugging session
+	 */
+	protected synchronized void setDebuggingConfig(ILaunchConfigurationWorkingCopy wc,
+					 			      String mode,
+					 			      ILaunch launch, 
+					 			      IProgressMonitor monitor) {
+		this.wc = wc;
+		this.mode = mode;
+		this.launch = launch;
+		this.monitor = monitor;
+	}
+	
+	private synchronized void clearDebuggingConfig() {
+		this.wc = null;
+		this.mode = null;
+		this.launch = null;
+		this.monitor = null;
+	}
+	
+}
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerRuntime.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerRuntime.java
new file mode 100644
index 0000000..f17fe52
--- /dev/null
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/ExternalServerRuntime.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 2005 BEA Systems, 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:
+ *    rfrost@bea.com - initial API and implementation
+ *    
+ * Based on GenericServerRuntime by Gorkem Ercan
+ *******************************************************************************/
+
+package org.eclipse.jst.server.generic.core.internal;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jst.server.generic.servertype.definition.ServerRuntime;
+
+/**
+ * Subclass of <code>GenericServerRuntime</code> that provides runtime server support for 
+ * servers that are started and stopped via external executables.
+ */
+public class ExternalServerRuntime extends GenericServerRuntime {
+	
+	/**
+	 * Override definition of validate to relax classpath and VM constraints.
+	 */
+	public IStatus validate() {
+		ServerRuntime serverTypeDefinition = getServerTypeDefinition();
+		
+		// we need to have a type definition
+        if(serverTypeDefinition == null) {
+		    return new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorNoServerType, null);
+        }
+        
+        // if there is a classpath definition, then want to make certain that there is an associated VM install
+        if(serverTypeDefinition.getClasspath()!= null && serverTypeDefinition.getClasspath().size() > 0) {
+    		if (getVMInstall() == null) {
+    			return new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorJRE, null);
+    		}
+        }
+        // check all defined classpaths
+        return validateClasspaths(serverTypeDefinition);
+	}
+	
+}
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerBehaviour.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerBehaviour.java
index 58a3d8c..218d12b 100644
--- a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerBehaviour.java
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerBehaviour.java
@@ -139,22 +139,25 @@
 			terminate();
 			return;
 		}
-
+		
+		shutdown(state);
+    }
+    
+    /**
+     * Shuts down the server via the launch configuration.
+     */
+    protected void shutdown(int state) {
+		GenericServerRuntime runtime = (GenericServerRuntime) getRuntimeDelegate();
 		try {
 			Trace.trace(Trace.FINEST, "Stopping Server");
 			if (state != IServer.STATE_STOPPED)
 				setServerState(IServer.STATE_STOPPING);
+			String configTypeID = getConfigTypeID(); 
 			ILaunchManager mgr = DebugPlugin.getDefault().getLaunchManager();
-
-			ILaunchConfigurationType type =
-				mgr.getLaunchConfigurationType(
-					IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION);
-
-			String launchName = "GenericServerStopper";
-			String uniqueLaunchName =
-				mgr.generateUniqueLaunchConfigurationNameFrom(launchName);
+			ILaunchConfigurationType type = mgr.getLaunchConfigurationType(configTypeID);
+			String launchName = getStopLaunchName();
+			String uniqueLaunchName = mgr.generateUniqueLaunchConfigurationNameFrom(launchName);
 			ILaunchConfiguration conf = null;
-
 			ILaunchConfiguration[] lch = mgr.getLaunchConfigurations(type);
 			for (int i = 0; i < lch.length; i++) {
 				if (launchName.equals(lch[i].getName())) {
@@ -169,43 +172,69 @@
 			} else {
 				wc = type.newInstance(null, uniqueLaunchName);
 			}
-			//To stop from appearing in history lists
-			wc.setAttribute(IDebugUIConstants.ATTR_PRIVATE, true);			
-	
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
-					getServerDefinition().getResolver().resolveProperties(this.getServerDefinition().getStop().getMainClass()));
-
-			GenericServerRuntime runtime = (GenericServerRuntime) getRuntimeDelegate();
-
-			IVMInstall vmInstall = runtime.getVMInstall();
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, runtime
-							.getVMInstallTypeId());
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME,
-					vmInstall.getName());
-
-			setupLaunchClasspath(wc, vmInstall, getStopClasspath());
-
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
-					getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getWorkingDirectory()));
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
-					getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getProgramArguments()));
-			wc.setAttribute(
-					IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,
-					getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getVmParameters()));				
+			
+			// To stop from appearing in history lists
+			wc.setAttribute(IDebugUIConstants.ATTR_PRIVATE, true);		
+			// Set the stop attribute so that we know we are stopping
 			wc.setAttribute(ATTR_STOP, "true");
+			
+			// Setup the launch config for stopping the server
+			setupStopLaunchConfiguration(runtime, wc);
+			
+			// Launch the stop launch config
 			wc.launch(ILaunchManager.RUN_MODE, new NullProgressMonitor());
+
 		} catch (Exception e) {
 			Trace.trace(Trace.SEVERE, "Error stopping Server", e);
 		}
-	
-
     }
 
+    /**
+     * Returns the String ID of the launch configuration type.
+     * @return
+     */
+	protected String getConfigTypeID() {
+		return IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION;
+	}
+
+	/**
+	 * Returns the String name of the stop launch configuration.
+	 * @return
+	 */
+	protected String getStopLaunchName() {
+		return "GenericServerStopper";
+	}
+	
+	/**
+	 * Sets up the launch configuration for stopping the server.
+	 * @param workingCopy
+	 */
+	protected void setupStopLaunchConfiguration(GenericServerRuntime runtime, ILaunchConfigurationWorkingCopy wc) {
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
+				getServerDefinition().getResolver().resolveProperties(this.getServerDefinition().getStop().getMainClass()));
+
+		IVMInstall vmInstall = runtime.getVMInstall();
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, runtime
+						.getVMInstallTypeId());
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME,
+				vmInstall.getName());
+
+		setupLaunchClasspath(wc, vmInstall, getStopClasspath());
+
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY,
+				getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getWorkingDirectory()));
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,
+				getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getProgramArguments()));
+		wc.setAttribute(
+				IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,
+				getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getVmParameters()));				
+	}
+
     public String getStartClassName() {
     	return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getMainClass());
     }
@@ -215,13 +244,10 @@
         return server.getServerDefinition();
     }
     
-    protected GenericServerRuntime getRuntimeDelegate()
-    {
+    protected GenericServerRuntime getRuntimeDelegate() {
        return (GenericServerRuntime)getServer().getRuntime().loadAdapter(GenericServerRuntime.class,null);
     }
 
-
-
     private List getStartClasspath() {
     	String cpRef = getServerDefinition().getStart().getClasspathReference();
     	return serverClasspath(cpRef);
@@ -296,21 +322,7 @@
     	return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getVmParameters());
     }
 
-    public void setupLaunchConfiguration(
-            ILaunchConfigurationWorkingCopy workingCopy,
-            IProgressMonitor monitor) throws CoreException {
-        if(getRuntimeDelegate().getServerTypeDefinition().getStart().getLaunchType()==null || getRuntimeDelegate().getServerTypeDefinition().getStart().getLaunchType().equals("java"))
-        	setupJavaLaunchConfiguration(workingCopy, monitor);
-        else
-        	setupExternalLaunchConfiguration(workingCopy, monitor);
-        	
-    }
-
-    private void setupExternalLaunchConfiguration(ILaunchConfigurationWorkingCopy workingCopy,IProgressMonitor monitor) throws CoreException {
-    
-    }
-    
-	private void setupJavaLaunchConfiguration(ILaunchConfigurationWorkingCopy workingCopy,IProgressMonitor monitor) throws CoreException {
+    public void setupLaunchConfiguration(ILaunchConfigurationWorkingCopy workingCopy, IProgressMonitor monitor) throws CoreException {
 		workingCopy.setAttribute(
                 IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME,
                 getStartClassName());
@@ -343,43 +355,44 @@
             workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,serverVMArgs);
         }
 	}
-    /**
-    	 * Setup for starting the server.
-    	 * 
-    	 * @param launch ILaunch
-    	 * @param launchMode String
-    	 * @param monitor IProgressMonitor
-    	 */
-    	protected void setupLaunch(ILaunch launch, String launchMode, IProgressMonitor monitor) throws CoreException {
-    		if ("true".equals(launch.getLaunchConfiguration().getAttribute(ATTR_STOP, "false")))
-    			return;
-    //		IStatus status = getRuntime().validate();
-    //		if (status != null && !status.isOK())
-    //			throw new CoreException(status);
     
+    /**
+     * Setup for starting the server.
+     * 
+     * @param launch ILaunch
+     * @param launchMode String
+     * @param monitor IProgressMonitor
+     */
+    protected void setupLaunch(ILaunch launch, String launchMode, IProgressMonitor monitor) throws CoreException {
+    	if ("true".equals(launch.getLaunchConfiguration().getAttribute(ATTR_STOP, "false"))) 
+    		return;
+    	//		IStatus status = getRuntime().validate();
+    	//		if (status != null && !status.isOK())
+    	//			throw new CoreException(status);
     	
-    		ServerPort[] ports = getServer().getServerPorts(null);
-    		ServerPort sp = null;
-    		for(int i=0;i<ports.length;i++){
-    			sp= ports[i];
-    			if (SocketUtil.isPortInUse(ports[i].getPort(), 5))
-    				throw new CoreException(new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.bind(GenericServerCoreMessages.errorPortInUse,Integer.toString(sp.getPort()),sp.getName()),null));
-    		}
-    		
-    		setServerState(IServer.STATE_STARTING);
-			setMode(launchMode);
-			
-    		// ping server to check for startup
-    		try {
-    			String url = "http://localhost";
-    			int port = sp.getPort();
-    			if (port != 80)
-    				url += ":" + port;
-    			ping = new PingThread(getServer(), url, 50, this);
-    		} catch (Exception e) {
-    			Trace.trace(Trace.SEVERE, "Can't ping for server startup.");
-    		}
+    	
+    	ServerPort[] ports = getServer().getServerPorts(null);
+    	ServerPort sp = null;
+    	for(int i=0;i<ports.length;i++){
+    		sp= ports[i];
+    		if (SocketUtil.isPortInUse(ports[i].getPort(), 5))
+    			throw new CoreException(new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.bind(GenericServerCoreMessages.errorPortInUse,Integer.toString(sp.getPort()),sp.getName()),null));
     	}
+    	
+    	setServerState(IServer.STATE_STARTING);
+    	setMode(launchMode);
+    	
+    	// ping server to check for startup
+    	try {
+    		String url = "http://localhost";
+    		int port = sp.getPort();
+    		if (port != 80)
+    			url += ":" + port;
+    		ping = new PingThread(getServer(), url, 50, this);
+    	} catch (Exception e) {
+    		Trace.trace(Trace.SEVERE, "Can't ping for server startup.");
+    	}
+    }
 
     protected void setProcess(final IProcess newProcess) {
     	if (process != null)
@@ -421,7 +434,7 @@
     /**
      * Terminates the server.
      */
-    private void terminate() {
+    protected void terminate() {
     	if (getServer().getServerState() == IServer.STATE_STOPPED)
     		return;
     
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.java
index 498f557..11b53a4 100644
--- a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.java
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.java
@@ -19,6 +19,12 @@
 	public static String errorMissingClasspathEntry;
 	public static String errorRemoveModuleAntpublisher;
 	public static String errorPublishAntpublisher;
+	public static String commandlineUnspecified;
+	public static String workingdirUnspecified;
+	public static String errorLaunchingExecutable;
+	public static String missingServer;
+	public static String externalStopLauncher;
+	public static String debugPortUnspecified;
 	static{
 		  NLS.initializeMessages(RESOURCE_BUNDLE, GenericServerCoreMessages.class);
 	}
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.properties b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.properties
index 7a1daba..580afff 100644
--- a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.properties
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerCoreMessages.properties
@@ -8,4 +8,10 @@
 moduleNotCompatible=Module type is not compatible
 errorNoClasspath=No classpath is defined
 errorRemoveModuleAntpublisher= Remove module failed using Ant publisher
-errorPublishAntpublisher= Publish failed using Ant publisher
\ No newline at end of file
+errorPublishAntpublisher= Publish failed using Ant publisher
+commandlineUnspecified=Executable commandline is unspecified.
+workingdirUnspecified=Working directory is unspecified or invalid.
+errorLaunchingExecutable=Error launching executable.
+missingServer=Server does not exist.
+externalStopLauncher=ExternalLaunchStopper
+debugPortUnspecified=Debugging port is unspecified.
diff --git a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerRuntime.java b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerRuntime.java
index 5457a0f..20b8076 100644
--- a/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerRuntime.java
+++ b/plugins/org.eclipse.jst.server.generic.core/src/org/eclipse/jst/server/generic/core/internal/GenericServerRuntime.java
@@ -99,14 +99,23 @@
 	 * @see org.eclipse.jst.server.core.IGenericRuntime#validate()
 	 */
 	public IStatus validate() {
-		if (getVMInstall() == null)
+		if (getVMInstall() == null) {
 			return new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorJRE, null);
-		
+		}
 		ServerRuntime serverTypeDefinition = getServerTypeDefinition();
-        if(serverTypeDefinition == null)
+        if(serverTypeDefinition == null) {
 		    return new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0, GenericServerCoreMessages.errorNoServerType, null);
-        if(serverTypeDefinition.getClasspath()== null || serverTypeDefinition.getClasspath().size()<1)
+        }
+		if(serverTypeDefinition.getClasspath()== null || serverTypeDefinition.getClasspath().size()<1) {
             return new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 0 ,GenericServerCoreMessages.errorNoClasspath,null);
+		}
+        return validateClasspaths(serverTypeDefinition);
+	}
+
+	/**
+	 * Checks all defined classpaths.
+	 */
+	protected IStatus validateClasspaths(ServerRuntime serverTypeDefinition) {
 		Iterator cpList  = serverTypeDefinition.getClasspath().iterator();
         while (cpList.hasNext()) {
 			Classpath cpth = (Classpath) cpList.next();
@@ -123,6 +132,7 @@
 		}
         return new Status(IStatus.OK, CorePlugin.PLUGIN_ID, 0, "", null);
 	}
+	
 	/**
 	 * Returns the ServerTypeDefinition for this runtime. 
 	 * Populated with the user properties if exists. 
diff --git a/plugins/org.eclipse.jst.server.generic.ui/plugin.xml b/plugins/org.eclipse.jst.server.generic.ui/plugin.xml
index 318f5c2..650f409 100644
--- a/plugins/org.eclipse.jst.server.generic.ui/plugin.xml
+++ b/plugins/org.eclipse.jst.server.generic.ui/plugin.xml
@@ -26,6 +26,11 @@
       configTypeID="org.eclipse.jst.server.generic.core.launchConfigurationType"
       icon="icons/obj16/server.gif">
     </launchConfigurationTypeImage>
+    <launchConfigurationTypeImage
+      id="org.eclipse.jst.server.generic.image.ui.ExternalLaunchConfigurationTypeImage"
+      configTypeID="org.eclipse.jst.server.generic.core.ExternalLaunchConfigurationType"
+      icon="icons/obj16/server.gif">
+    </launchConfigurationTypeImage>
   </extension>
   
   <extension point="org.eclipse.debug.ui.launchConfigurationTabGroups">
@@ -34,6 +39,11 @@
       type="org.eclipse.jst.server.generic.core.launchConfigurationType"
       class="org.eclipse.jst.server.generic.ui.internal.GenericLaunchConfigurationTabGroup">
     </launchConfigurationTabGroup>
+    <launchConfigurationTabGroup
+      id="org.eclipse.jst.server.generic.ui.internal.launchConfigurationTabGroup"
+      type="org.eclipse.jst.server.generic.core.ExternalLaunchConfigurationType"
+      class="org.eclipse.jst.server.generic.ui.internal.GenericLaunchConfigurationTabGroup">
+    </launchConfigurationTabGroup>
   </extension>
 
 </plugin>