/*************************************************************************************************** * Copyright (c) 2005 Eteration A.S. and Gorkem Ercan. 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: Gorkem Ercan - initial API and implementation * **************************************************************************************************/ package org.eclipse.jst.server.generic.core.internal; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.model.IProcess; import org.eclipse.debug.ui.IDebugUIConstants; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.IRuntimeClasspathEntry; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jst.server.generic.servertype.definition.ArgumentPair; import org.eclipse.jst.server.generic.servertype.definition.LaunchConfiguration; import org.eclipse.jst.server.generic.servertype.definition.ServerRuntime; import org.eclipse.osgi.util.NLS; import org.eclipse.wst.server.core.IModule; import org.eclipse.wst.server.core.IServer; import org.eclipse.wst.server.core.ServerPort; import org.eclipse.wst.server.core.model.ServerBehaviourDelegate; import org.eclipse.wst.server.core.model.ServerDelegate; import org.eclipse.wst.server.core.util.SocketUtil; /** * Server behavior delegate implementation for generic server. * * @author Gorkem Ercan */ public class GenericServerBehaviour extends ServerBehaviourDelegate { public static final String ATTR_STOP = "stop-server"; //$NON-NLS-1$ public static final String ATTR_SERVER_ID = "server-id"; //$NON-NLS-1$ // the thread used to ping the server to check for startup protected transient PingThread ping; protected transient IDebugEventSetListener processListener; protected transient IProcess process; /* (non-Javadoc) * @see org.eclipse.wst.server.core.model.ServerBehaviourDelegate#publishServer(org.eclipse.core.runtime.IProgressMonitor) */ public void publishServer(int kind, IProgressMonitor monitor) throws CoreException { // do nothing } /* (non-Javadoc) * @see org.eclipse.wst.server.core.model.ServerBehaviourDelegate#publishModule(org.eclipse.wst.server.core.IModule[], org.eclipse.wst.server.core.IModule, org.eclipse.core.runtime.IProgressMonitor) */ public void publishModule(int kind, int deltaKind, IModule[] module, IProgressMonitor monitor) throws CoreException { GenericPublisher publisher = initializePublisher( kind, deltaKind, module ); IStatus[] status = null; if(REMOVED == deltaKind ){//TODO: check if the removed module is published to server status = publisher.unpublish(monitor); } else{ checkClosed(module); status= publisher.publish(null,monitor); } setModulePublishState( module, status ); } private void setModulePublishState( IModule[] module, IStatus[] status ) throws CoreException { if( module==null ) return; for( int i=0; i < module.length; i++) { if(status == null || status.length < i || status[i]==null || status[i].getSeverity() == IStatus.OK ) { setModulePublishState(module, IServer.PUBLISH_STATE_NONE); } else { if ( IStatus.ERROR == status[i].getSeverity() ){ setModulePublishState( module, IServer.PUBLISH_STATE_UNKNOWN ); throw new CoreException( status[i] ); } } } } private void checkClosed(IModule[] module) throws CoreException { for( int i=0; i < module.length; i++ ){ if( !module[i].exists() ){ IStatus status = new Status(IStatus.ERROR,CorePlugin.PLUGIN_ID,0, NLS.bind(GenericServerCoreMessages.canNotPublishDeletedModule,module[i].getName()),null); throw new CoreException(status); } } } private GenericPublisher initializePublisher(int kind, int deltaKind, IModule[] module ) throws CoreException { String publisherId = ServerTypeDefinitionUtil.getPublisherID(module[0], getServerDefinition()); GenericPublisher publisher = PublishManager.getPublisher(publisherId); if(publisher==null){ IStatus status = new Status(IStatus.ERROR,CorePlugin.PLUGIN_ID,0,NLS.bind(GenericServerCoreMessages.unableToCreatePublisher,publisherId),null); throw new CoreException(status); } publisher.initialize( module,getServer(), kind, deltaKind ); return publisher; } /* (non-Javadoc) * @see org.eclipse.wst.server.core.model.ServerBehaviourDelegate#stop(boolean) */ public void stop(boolean force) { if (force) { terminate(); return; } int state = getServer().getServerState(); if (state == IServer.STATE_STOPPED) return; else if (state == IServer.STATE_STARTING || state == IServer.STATE_STOPPING) { terminate(); return; } shutdown(state); } /** * Shuts down the server via the launch configuration. */ protected void shutdown(int state) { GenericServerRuntime runtime = getRuntimeDelegate(); try { Trace.trace(Trace.FINEST, "Stopping Server"); //$NON-NLS-1$ if (state != IServer.STATE_STOPPED) setServerState(IServer.STATE_STOPPING); String configTypeID = getConfigTypeID(); ILaunchManager mgr = DebugPlugin.getDefault().getLaunchManager(); 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())) { conf = lch[i]; break; } } ILaunchConfigurationWorkingCopy wc = null; if (conf != null) { wc = conf.getWorkingCopy(); } else { wc = type.newInstance(null, uniqueLaunchName); } // 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"); //$NON-NLS-1$ // Set the server ID so that we can distinguish stops wc.setAttribute( ATTR_SERVER_ID, this.getServer().getId()); // 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); //$NON-NLS-1$ } } /** * Returns the String ID of the launch configuration type. * @return id */ protected String getConfigTypeID() { return IJavaLaunchConfigurationConstants.ID_JAVA_APPLICATION; } /** * Returns the String name of the stop launch configuration. * @return launchname */ protected String getStopLaunchName() { return "GenericServerStopper"; //$NON-NLS-1$ } private boolean isRemote(){ return (getServer().getServerType().supportsRemoteHosts()&& !SocketUtil.isLocalhost(getServer().getHost()) ); } /** * Sets up the launch configuration for stopping the server. */ protected void setupStopLaunchConfiguration(GenericServerRuntime runtime, ILaunchConfigurationWorkingCopy wc) { if(isRemote())// Do not launch for remote servers. return; 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()); Map environVars = getEnvironmentVariables(getServerDefinition().getStop()); if(!environVars.isEmpty()){ wc.setAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES,environVars); } wc.setAttribute( IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getWorkingDirectory())); wc.setAttribute( IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getProgramArgumentsAsString())); wc.setAttribute( IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS, getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStop().getVmParametersAsString())); } /** * Start class name * @return name */ public String getStartClassName() { return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getMainClass()); } /** * Server definition * @return serverdef */ public ServerRuntime getServerDefinition() { GenericServer server = (GenericServer)getServer().loadAdapter(ServerDelegate.class, null); return server.getServerDefinition(); } protected GenericServerRuntime getRuntimeDelegate() { return (GenericServerRuntime)getServer().getRuntime().loadAdapter(GenericServerRuntime.class,null); } private List getStartClasspath() { String cpRef = getServerDefinition().getStart().getClasspathReference(); return serverClasspath(cpRef); } /** * @param cpRef * @return classpath */ protected List serverClasspath(String cpRef) { return ServerTypeDefinitionUtil.getClasspathEntries(cpRef, getServerDefinition(),true); } /** * @param wc * @param vmInstall */ @SuppressWarnings("unchecked") protected void setupLaunchClasspath(ILaunchConfigurationWorkingCopy wc, IVMInstall vmInstall, List cp) { //merge existing classpath with server classpath try { IRuntimeClasspathEntry[] existingCps = JavaRuntime.computeUnresolvedRuntimeClasspath(wc); for (int i = 0; i < existingCps.length; i++) { if(cp.contains(existingCps[i])==false){ cp.add(existingCps[i]); } } } catch (CoreException e) { // ignore } wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_CLASSPATH, convertCPEntryToMemento(cp)); wc.setAttribute(IJavaLaunchConfigurationConstants.ATTR_DEFAULT_CLASSPATH,false); } private List convertCPEntryToMemento(List cpEntryList) { List<String> list = new ArrayList<String>(cpEntryList.size()); Iterator iterator = cpEntryList.iterator(); while(iterator.hasNext()) { IRuntimeClasspathEntry entry = (IRuntimeClasspathEntry)iterator.next(); try { list.add(entry.getMemento()); } catch (CoreException e) { // ignore } } return list; } private String getWorkingDirectory() { return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getWorkingDirectory()); } protected String getProgramArguments() { return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getProgramArgumentsAsString()); } protected Map getEnvironmentVariables(LaunchConfiguration config){ List variables = config.getEnvironmentVariable(); Map<String, String> varsMap = new HashMap<String, String>(variables.size()); Iterator iterator= variables.iterator(); while(iterator.hasNext()){ ArgumentPair pair = (ArgumentPair)iterator.next(); varsMap.put(pair.getName(),getServerDefinition().getResolver().resolveProperties(pair.getValue())); } return varsMap; } private String getVmArguments() { return getServerDefinition().getResolver().resolveProperties(getServerDefinition().getStart().getVmParametersAsString()); } public void setupLaunchConfiguration(ILaunchConfigurationWorkingCopy workingCopy, IProgressMonitor monitor) throws CoreException { if(isRemote())// No launch for remote servers. return; workingCopy.setAttribute( IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, getStartClassName()); GenericServerRuntime runtime = getRuntimeDelegate(); IVMInstall vmInstall = runtime.getVMInstall(); if (vmInstall == null ) vmInstall = JavaRuntime.getDefaultVMInstall(); workingCopy.setAttribute( IJavaLaunchConfigurationConstants.ATTR_JRE_CONTAINER_PATH, JavaRuntime.newJREContainerPath(vmInstall).toPortableString()); setupLaunchClasspath(workingCopy, vmInstall, getStartClasspath()); workingCopy.setAttribute( IJavaLaunchConfigurationConstants.ATTR_WORKING_DIRECTORY, getWorkingDirectory()); 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 ) { workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS,serverProgArgs); } String existingVMArgs = workingCopy.getAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,(String)null); String serverVMArgs= getVmArguments(); if( existingVMArgs==null ) { workingCopy.setAttribute(IJavaLaunchConfigurationConstants.ATTR_VM_ARGUMENTS,serverVMArgs); } } /** * Setup for starting the server. Checks all ports available * and sets server state and mode. * * @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"))) //$NON-NLS-1$ //$NON-NLS-2$ return; String host = getServer().getHost(); ServerPort[] ports = getServer().getServerPorts(null); ServerPort sp = null; if(SocketUtil.isLocalhost(host)){ 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, NLS.bind(GenericServerCoreMessages.errorPortInUse,Integer.toString(sp.getPort()),sp.getName()),null)); } } setServerState(IServer.STATE_STARTING); setMode(launchMode); } /** * Call to start Ping thread that will check for startup of the server. * */ protected void startPingThread() { try { String url = "http://"+getServer().getHost(); //$NON-NLS-1$ ServerPort[] ports = getServer().getServerPorts(null); ServerPort sp = null; for(int i=0;i<ports.length;i++){ if(ports[i].getProtocol().equalsIgnoreCase("http")){//$NON-NLS-1$ sp=ports[i]; } } if(sp==null){ Trace.trace(Trace.SEVERE, "Can't ping for server startup."); //$NON-NLS-1$ return; } int port = sp.getPort(); if (port != 80) url += ":" + port; //$NON-NLS-1$ ping = new PingThread(getServer(), url, this); } catch (Exception e) { Trace.trace(Trace.SEVERE, "Can't ping for server startup."); //$NON-NLS-1$ } } protected void setProcess(final IProcess newProcess) { if (process != null) return; if(processListener!=null) DebugPlugin.getDefault().removeDebugEventListener(processListener); if (newProcess==null) return; process = newProcess; processListener = new IDebugEventSetListener() { public void handleDebugEvents(DebugEvent[] events) { if (events != null) { int size = events.length; for (int i = 0; i < size; i++) { if (process!= null && process.equals(events[i].getSource()) && events[i].getKind() == DebugEvent.TERMINATE) { DebugPlugin.getDefault().removeDebugEventListener(this); stopImpl(); } } } } }; DebugPlugin.getDefault().addDebugEventListener(processListener); } protected void stopImpl() { if (ping != null) { ping.stop(); ping = null; } if (process != null) { process = null; DebugPlugin.getDefault().removeDebugEventListener(processListener); processListener = null; } setServerState(IServer.STATE_STOPPED); } /** * Terminates the server. * This method may be called before a process created while setting up the * launch config. */ protected void terminate() { if (getServer().getServerState() == IServer.STATE_STOPPED) return; try { setServerState(IServer.STATE_STOPPING); Trace.trace(Trace.FINEST, "Killing the Server process"); //$NON-NLS-1$ if (process != null && !process.isTerminated()) { process.terminate(); } stopImpl(); } catch (Exception e) { Trace.trace(Trace.SEVERE, "Error killing the process", e); //$NON-NLS-1$ } } private List getStopClasspath() { String cpRef = getServerDefinition().getStop().getClasspathReference(); return serverClasspath(cpRef); } public void publishFinish(IProgressMonitor monitor) throws CoreException { IModule[] modules = this.getServer().getModules(); boolean allpublished= true; for (int i = 0; i < modules.length; i++) { if(this.getServer().getModulePublishState(new IModule[]{modules[i]})!=IServer.PUBLISH_STATE_NONE) allpublished=false; } if(allpublished) setServerPublishState(IServer.PUBLISH_STATE_NONE); } protected void setServerStarted() { setServerState(IServer.STATE_STARTED); } public IPath getTempDirectory(){ return super.getTempDirectory(); } }