package org.radrails.server.core.launching;
import java.util.Collection;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
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.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchListener;
import org.radrails.rails.internal.core.RailsPlugin;
import org.radrails.server.core.IServerConstants;
import org.radrails.server.core.Server;
import org.radrails.server.core.ServerLog;
import org.radrails.server.core.ServerManager;
import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants;
/**
* This class listens to launches and tries to hook up launches of servers to the Server object in the ServerManager.
* This de-coupling allows us to handle servers launched form the Run or Debug menu equivalent to those launched from
* the Servers view.
*
* TODO Still need to handle a server launched via Run/Debug menus that has no corresponding server in the ServerManager. Create one?
* @author Chris Williams
*
*/
public class ServerLaunchListener implements ILaunchListener {
public void launchRemoved(ILaunch launch) {
}
public void launchChanged(final ILaunch launch) {
final Server matching = grabLaunchedServer(launch);
if (matching == null) return;
// a server's launch now has it's processes, attach the server to the process
Job job = new Job("")
{
protected IStatus run(IProgressMonitor monitor)
{
matching.started(launch.getProcesses()[0]);
return Status.OK_STATUS;
}
};
job.schedule();
}
public void launchAdded(ILaunch launch) {
Server matching = grabLaunchedServer(launch);
if (matching == null) return;
// a server has been launched, set it's status to started and alert listeners
matching.updateStatus(IServerConstants.STARTING);
}
private Server grabLaunchedServer(ILaunch launch) {
try {
ILaunchConfiguration config = launch.getLaunchConfiguration();
if (config == null) return null;
String typeId = config.getType().getIdentifier();
if (typeId.equals(IRailsAppLaunchConfigurationConstants.LAUNCH_TYPE_ID)) {
return null;
}
String filename = config.getAttribute(IRubyLaunchConfigurationConstants.ATTR_FILE_NAME, (String)null);
if (!looksLikeServerLaunchFile(filename)) return null;
String projectName = config.getAttribute(IRubyLaunchConfigurationConstants.ATTR_PROJECT_NAME, (String) null);
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
Collection<Server> servers = ServerManager.getInstance().getServersForProject(project);
return findMatchingServer(config, servers);
} catch (CoreException e) {
ServerLog.log(e);
}
return null;
}
/**
* Determine if a filename corresponds to file that launches Rails servers...
* @param filename
* @return
*/
private boolean looksLikeServerLaunchFile(String filename) {
if (filename == null) return false;
if (filename.endsWith("gem")) return false; // Specifically avoid doing any more work if this is a launch of rubygems!
if (filename.endsWith("script/server") || filename.endsWith("script\\server"))return true; // normal rails script/server
// If we do a pure comparison with mongrel path we can get into an infinite loop if this launch is a rubygems one to get the rubygems installation path
// we should narrow the comparison more to avoid that
return filename.endsWith("mongrel_rails") && filename.equals(RailsPlugin.getInstance().getMongrelPath());
}
private Server findMatchingServer(ILaunchConfiguration config, Collection<Server> servers) {
if (servers == null || servers.isEmpty()) return null;
if (servers.size() == 1) return servers.iterator().next();
try {
String args = config.getAttribute(IRubyLaunchConfigurationConstants.ATTR_PROGRAM_ARGUMENTS, "");
for (Server server : servers) {
// Check the args and find the one who's environment/port/type match
if (args.equals(server.getProgramArguments())) {
return server;
}
}
} catch (CoreException e) {
ServerLog.log(e);
}
return null;
}
}