| /******************************************************************************* |
| * 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 java.util.Map; |
| 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.ILaunch; |
| import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; |
| import org.eclipse.debug.core.ILaunchManager; |
| import org.eclipse.debug.core.model.IProcess; |
| 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.osgi.util.NLS; |
| import org.eclipse.wst.server.core.IServer; |
| import org.eclipse.wst.server.core.ServerPort; |
| import org.eclipse.wst.server.core.util.SocketUtil; |
| |
| /** |
| * 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 fLaunchConfigurationWC; |
| private String fMode; |
| private ILaunch fLaunch; |
| private IProgressMonitor fProgressMonitor; |
| |
| /** |
| * Override to reset the status if the state was unknown |
| * @param force |
| */ |
| public void stop(boolean force) { |
| resetStatus(getServer().getServerState()); |
| super.stop(force); |
| } |
| |
| /** |
| * Override to set status to unknown if the port was in use and to reset the status if the state was |
| * unknown and an exception was not thrown. Will want to change logic once external generic server pings |
| * server process to determine state instead of maintaining handle to process. |
| */ |
| protected void setupLaunch(ILaunch launch, String launchMode, IProgressMonitor monitor) throws CoreException { |
| int state = getServer().getServerState(); |
| try { |
| super.setupLaunch(launch, launchMode, monitor); |
| } catch (CoreException ce) { |
| ServerPort portInUse = portInUse(); |
| if (portInUse != null) { |
| Trace.trace(Trace.WARNING, "Port " + portInUse.getPort() + " is currently in use"); //$NON-NLS-1$//$NON-NLS-2$ |
| Status status = new Status(IStatus.WARNING, CorePlugin.PLUGIN_ID, IStatus.OK, |
| NLS.bind(GenericServerCoreMessages.errorPortInUse,Integer.toString(portInUse.getPort()),portInUse.getName()), null); |
| setServerStatus(status); |
| setServerState(IServer.STATE_UNKNOWN); |
| } |
| throw ce; |
| } |
| resetStatus(state); |
| } |
| |
| private ServerPort portInUse() { |
| ServerPort[] ports = getServer().getServerPorts(null); |
| ServerPort sp; |
| for(int i=0;i<ports.length;i++){ |
| sp = ports[i]; |
| if (SocketUtil.isPortInUse(sp.getPort(), 5)) { |
| return sp; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Override to trigger the launch of the debugging session (if appropriate). |
| */ |
| protected synchronized void setServerStarted() { |
| if (fLaunchConfigurationWC != null) { |
| try { |
| setupSourceLocator( fLaunch ); |
| ExternalLaunchConfigurationDelegate.startDebugging(fLaunchConfigurationWC, fMode, fLaunch, fProgressMonitor); |
| } catch (CoreException ce) { |
| // failed to start debugging, so set mode to run |
| setMode(ILaunchManager.RUN_MODE); |
| final Status status = new Status(IStatus.ERROR, CorePlugin.PLUGIN_ID, 1, |
| GenericServerCoreMessages.errorStartingExternalDebugging, ce); |
| CorePlugin.getDefault().getLog().log(status); |
| Trace.trace(Trace.SEVERE, GenericServerCoreMessages.errorStartingExternalDebugging, ce); |
| } finally { |
| clearDebuggingConfig(); |
| } |
| } |
| setServerState(IServer.STATE_STARTED); |
| } |
| |
| /** |
| * Subclasses may override this method to replace default source locator or add additional |
| * sourceLookupParticipant, if necessary |
| * @param launch the ILaunch object of the debug session |
| */ |
| protected void setupSourceLocator(ILaunch launch) { |
| //nothing to do |
| } |
| |
| /* |
| * If the server state is unknown, reset the status to OK |
| */ |
| private void resetStatus(int state) { |
| if (state == IServer.STATE_UNKNOWN) { |
| setServerStatus(null); |
| } |
| } |
| |
| /** |
| * 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; |
| |
| // cache a ref to the current process |
| IProcess currentProcess = process; |
| // set the process var to null so that GenericServerBehavior.setProcess() |
| // will grab the stop executable (and declare the server stopped when it exits) |
| process = null; |
| |
| // execute the standard shutdown |
| shutdown(state); |
| |
| // if the shutdown did not terminate the process, forcibly terminate it |
| try { |
| if (currentProcess != null && !currentProcess.isTerminated()) { |
| Trace.trace(Trace.FINER, "About to kill process: " + currentProcess); //$NON-NLS-1$ |
| currentProcess.terminate(); |
| currentProcess = null; |
| } |
| } catch (Exception e) { |
| Trace.trace(Trace.SEVERE, "Error killing the process", e); //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * Override superclass method to correctly setup the launch configuration for starting an external |
| * server. |
| * @param workingCopy |
| * @param monitor |
| * @throws CoreException |
| */ |
| 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())); |
| workingCopy.setAttribute(ExternalLaunchConfigurationDelegate.HOST, getServer().getHost()); |
| |
| // just use the commandline for now |
| workingCopy.setAttribute(ExternalLaunchConfigurationDelegate.EXECUTABLE_NAME, external); |
| Map environVars = getEnvironmentVariables(getServerDefinition().getStart()); |
| if(!environVars.isEmpty()){ |
| workingCopy.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES,environVars); |
| } |
| String existingProgArgs = workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, (String)null); |
| String serverProgArgs = getProgramArguments(); |
| if(existingProgArgs==null || existingProgArgs.indexOf(serverProgArgs)<0) { |
| workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,serverProgArgs); |
| } |
| } |
| |
| /* |
| * 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(); //$NON-NLS-1$ |
| 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 launchTypeID |
| */ |
| protected String getConfigTypeID() { |
| return ExternalLaunchConfigurationDelegate.ID_EXTERNAL_LAUNCH_TYPE; |
| } |
| |
| /** |
| * Returns the String name of the stop launch configuration. |
| * @return launcherName |
| */ |
| protected String getStopLaunchName() { |
| return GenericServerCoreMessages.externalStopLauncher; |
| } |
| |
| /** |
| * Sets up the launch configuration for stopping the server. |
| * |
| */ |
| 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 |
| Map environVars = getEnvironmentVariables(getServerDefinition().getStop()); |
| if(!environVars.isEmpty()){ |
| wc.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES,environVars); |
| } |
| wc.setAttribute( |
| IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, |
| resolver.resolveProperties(serverDef.getStop().getProgramArgumentsAsString())); |
| wc.setAttribute(ExternalLaunchConfigurationDelegate.EXECUTABLE_NAME, external); |
| wc.setAttribute(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.fLaunchConfigurationWC = wc; |
| this.fMode = mode; |
| this.fLaunch = launch; |
| this.fProgressMonitor = monitor; |
| } |
| |
| private synchronized void clearDebuggingConfig() { |
| this.fLaunchConfigurationWC = null; |
| this.fMode = null; |
| this.fLaunch = null; |
| this.fProgressMonitor = null; |
| } |
| |
| |
| } |