package org.radrails.server.internal.ui.launching;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Collection;
import java.util.Observable;
import java.util.Observer;
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.Platform;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.model.LaunchConfigurationDelegate;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PartInitException;
import org.radrails.rails.ui.browser.BrowserUtil;
import org.radrails.server.core.IServerConstants;
import org.radrails.server.core.Server;
import org.radrails.server.core.ServerManager;
import org.radrails.server.core.launching.IRailsAppLaunchConfigurationConstants;
import org.radrails.server.internal.ui.ServerUILog;
import org.rubypeople.rdt.internal.ui.wizards.dialogfields.ComboDialogField;
public class RailsAppLaunchConfigurationDelegate extends LaunchConfigurationDelegate
{
public void launch(final ILaunchConfiguration configuration, String mode, ILaunch launch, IProgressMonitor monitor)
throws CoreException
{
Server s = getServerForLaunch(configuration);
if (s == null)
{
// Ask user to explicitly choose a server!
IProject project = getProject(configuration);
if (project != null)
{
Collection<Server> servers = ServerManager.getInstance().getServersForProject(project);
ServerChoiceRunnable runnable = new ServerChoiceRunnable(servers);
Display.getDefault().syncExec(runnable);
s = runnable.getServer();
if (s != null)
{
try
{
ILaunchConfigurationWorkingCopy wc = configuration.getWorkingCopy();
wc.setAttribute(IRailsAppLaunchConfigurationConstants.SERVER_NAME, s.getName());
wc.doSave();
}
catch (CoreException e)
{
ServerUILog.log(e);
}
}
}
}
if (s != null)
{
if (s.isStopped())
{
s.updateRunMode(mode);
s.start(false);
}
if (configuration.getAttribute(IRailsAppLaunchConfigurationConstants.LAUNCH_BROWSER, false))
{
LaunchBrowserThread t = new LaunchBrowserThread(s, configuration);
if (s.isStarted())
{
t.started();
}
else
{
ServerManager.getInstance().addServerObserver(t);
}
}
}
}
private Server getServerForLaunch(ILaunchConfiguration config)
{
try
{
String serverName = config.getAttribute(IRailsAppLaunchConfigurationConstants.SERVER_NAME, "");
if (serverName != null && serverName.trim().length() > 0)
{
Server s = ServerManager.getInstance().getServer(serverName);
if (s != null)
{
// TODO Ensure that the server is actually tied to the project we're trying to launch!
return s;
}
}
IProject project = getProject(config);
if (project == null)
return null;
Collection<Server> servers = ServerManager.getInstance().getServersForProject(project);
if (servers != null && servers.size() == 1)
return servers.iterator().next();
}
catch (CoreException e)
{
ServerUILog.logError("error reading launch config attributes", e);
}
return null;
}
private IProject getProject(ILaunchConfiguration config) throws CoreException
{
String projectName = config.getAttribute(IRailsAppLaunchConfigurationConstants.PROJECT_NAME, (String) null);
if (projectName == null)
return null;
return ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
}
private String getLaunchUrl(Server server, ILaunchConfiguration config) throws CoreException
{
// figure out base URL from server and port
String baseUrl = "http://" + server.getBrowserHost() + ":" + server.getPort();
String actionUrl = config.getAttribute(IRailsAppLaunchConfigurationConstants.ACTION_PATH, "");
// append a leading slash if not present
if (!actionUrl.startsWith("/"))
{
actionUrl = "/" + actionUrl;
}
return baseUrl + actionUrl;
}
private class LaunchBrowserThread implements Observer
{
private Server server;
private ILaunchConfiguration config;
public LaunchBrowserThread(Server s, ILaunchConfiguration c)
{
server = s;
config = c;
}
public void started()
{
try
{
launchBrowser(server, config);
}
catch (CoreException e)
{
ServerUILog.logError("Error launching browser", e);
}
catch (IOException e)
{
ServerUILog.logError("Error launching browser", e);
}
}
public void update(Observable arg0, Object arg1)
{
Server serv = (Server) arg0;
String action = (String) arg1;
if (serv.getName().equals(server.getName()) && action.equals(IServerConstants.UPDATE))
{
if (serv.getStatus().equals(IServerConstants.STARTED))
{
started();
}
}
}
private void launchBrowser(Server server, ILaunchConfiguration config) throws CoreException, IOException
{
final String launchUrl = getLaunchUrl(server, config);
ServerUILog.logInfo("launching this url: " + launchUrl, null);
if (config.getAttribute(IRailsAppLaunchConfigurationConstants.USE_EXTERNAL_BROWSER, false))
{
String browserExe = config.getAttribute(IRailsAppLaunchConfigurationConstants.BROWSER_EXE, "");
if (browserExe != null && !browserExe.equals("") && new File(browserExe).exists())
{
if (Platform.getOS().equals(Platform.OS_MACOSX))
{
Runtime.getRuntime().exec(new String[] { "open", browserExe, launchUrl });
}
else
{
Runtime.getRuntime().exec(new String[] { browserExe, launchUrl });
}
}
}
else if (config.getAttribute(IRailsAppLaunchConfigurationConstants.USE_INTERNAL_BROWSER, false))
{
// launch the internal browser
Display.getDefault().asyncExec(new Runnable()
{
public void run()
{
try
{
BrowserUtil.openOrActivateBrowser(launchUrl);
}
catch (PartInitException e)
{
ServerUILog.log(e);
}
catch (MalformedURLException e)
{
ServerUILog.log(e);
}
}
});
}
ServerManager.getInstance().deleteServerObserver(this);
}
}
private class ChooseServerDialog extends Dialog
{
private Collection<Server> servers;
private ComboDialogField serverField;
protected ChooseServerDialog(Shell parentShell, Collection<Server> servers)
{
super(parentShell);
this.servers = servers;
serverField = new ComboDialogField(SWT.DROP_DOWN | SWT.READ_ONLY);
serverField.setLabelText("Server:");
String[] names = new String[servers.size()];
int i = 0;
for (Server server : servers)
{
names[i++] = server.getName();
}
serverField.setItems(names);
serverField.setText(servers.iterator().next().getName());
}
protected void configureShell(Shell newShell)
{
super.configureShell(newShell);
newShell.setText("Choose server");
}
public Server getServer()
{
String name = serverField.getText();
for (Server server : servers)
{
if (server.getName().equals(name))
return server;
}
return null;
}
@Override
protected Control createDialogArea(Composite parent)
{
Composite composite = (Composite) super.createDialogArea(parent);
Composite control = new Composite(composite, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
control.setLayout(layout);
Label label = new Label(control, SWT.WRAP);
label
.setText("We are unable to find the server previously associated with this launch. Please choose one of the existing servers to use for launching this Rails Application.");
GridData data = new GridData();
data.horizontalSpan = 2;
data.widthHint = 300;
label.setLayoutData(data);
serverField.doFillIntoGrid(control, 2);
return composite;
}
}
private class ServerChoiceRunnable implements Runnable
{
private Collection<Server> servers;
private Server server;
public ServerChoiceRunnable(Collection<Server> servers)
{
this.servers = servers;
}
public void run()
{
ChooseServerDialog dialog = new ChooseServerDialog(Display.getDefault().getActiveShell(), servers);
if (dialog.open() == Dialog.OK)
{
server = dialog.getServer();
}
}
public Server getServer()
{
return server;
}
}
}