/*******************************************************************************
* Copyright (c) 2010 Eric Bodden.
* 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:
* Eric Bodden - initial API and implementation
******************************************************************************/
package de.bodden.tamiflex.launching;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Date;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.internal.ui.DebugUIPlugin;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.dialogs.ContainerSelectionDialog;
import org.osgi.framework.Bundle;
import de.bodden.tamiflex.Activator;
import de.bodden.tamiflex.views.OnlineMonitorNode;
import de.bodden.tamiflex.views.ReflectionView;
import de.bodden.tamiflex.views.ReflectionViewContentInserter;
import de.bodden.tamiflex.views.TreeParent;
@SuppressWarnings("restriction")
public class LaunchUtil {
public static class FolderSelectionDialog extends ContainerSelectionDialog {
private final String SETTINGS_ID = IDebugUIConstants.PLUGIN_ID + ".SHARED_LAUNCH_CONFIGURATON_DIALOG"; //$NON-NLS-1$
public FolderSelectionDialog(Shell parentShell, IContainer initialRoot, String message) {
super(parentShell, initialRoot, true, message);
}
protected IDialogSettings getDialogBoundsSettings() {
IDialogSettings settings = DebugUIPlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(SETTINGS_ID);
if (section == null) {
section = settings.addNewSection(SETTINGS_ID);
}
return section;
}
}
public static String[] openSocketAndUpdateEnvironment(
ILaunchConfiguration configuration, String[] environment) throws CoreException {
String hostNameAndPort = LaunchUtil.openSocket(configuration);
if(environment==null) environment = new String[0];
String[] newEnv = new String[environment.length+1];
System.arraycopy(environment, 0, newEnv, 1, environment.length);
newEnv[0] = "TAMIFLEX_ECLIPSE="+hostNameAndPort;
return newEnv;
}
public static String appendAgentArgs(String otherArgs, boolean playIn) {
StringBuilder vmArguments = new StringBuilder(otherArgs);
if(!otherArgs.isEmpty()) vmArguments.append(" "); //make sure to separate our arguments from any others
vmArguments.append("-javaagent:");
String localPath = playIn ? "lib/pia.jar" : "lib/poa.jar";
vmArguments.append(LaunchUtil.getAgentJarPath(localPath));
return vmArguments.toString();
}
private static String openSocket(final ILaunchConfiguration configuration) {
final ServerSocket serverSocket;
try {
serverSocket = new ServerSocket(0);
String host = serverSocket.getInetAddress().getHostAddress();
int port = serverSocket.getLocalPort();
String projectName;
try {
projectName = configuration.getAttribute(IJavaLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
} catch (CoreException e1) {
e1.printStackTrace();
projectName = "";
}
final IProject project = (IProject) ResourcesPlugin.getWorkspace().getRoot().findMember(projectName);
new Thread("SocketListener") {
private ReflectionView reflView;
@Override
public void run() {
Display.getDefault().syncExec(new Runnable() {
public void run() {
try {
IWorkbenchPage activePage = Activator.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage();
activePage.showView(ReflectionView.ID);
reflView = (ReflectionView) activePage.findView(ReflectionView.ID);
} catch (PartInitException e) {
e.printStackTrace();
}
}
});
TreeParent root = reflView.getContentProvider().getRoot();
OnlineMonitorNode socketRoot;
String rootLabel = configuration.getName()+" - "+new Date().toString();
socketRoot = new OnlineMonitorNode(project, rootLabel);
root.addChild(socketRoot);
Socket socket=null;
InputStream is=null;
final ReflectionViewContentInserter contentInserter =
new ReflectionViewContentInserter(socketRoot, reflView);
try {
socket = serverSocket.accept();
is = socket.getInputStream();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
String line = r.readLine();
if(line!=null) {
//POA first sends absolute path of log file; this we then register with the LogFileDatabase
File logFile = new File(line);
Activator.getDefault().getLogFileDatabase().registerLogFile(project, logFile);
while((line=r.readLine())!=null) {
contentInserter.insertFromTraceFileLine(line);
Display.getDefault().asyncExec(new Runnable() {
public void run() {
reflView.refresh();
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(socket!=null) socket.close();
if(is!=null) is.close();
if(serverSocket!=null) serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
contentInserter.removeUnusedNodes();
}
}
}.start();
//allow other thread to get to the point where we
//accept connections on the server socket before we proceed here
Thread.yield();
return host + ":" +port;
} catch (IOException e) {
throw new RuntimeException("Problem creating server socket",e);
}
}
public static String getAgentJarPath(String localPath) {
StringBuffer cpath = new StringBuffer();
// This returns the bundle with the highest version or null if none
// found
// - for Eclipse 3.0 compatibility
Bundle pluginBundle = Platform.getBundle(Activator.PLUGIN_ID);
URL resolved = null;
// 3.0 using bundles instead of plugin descriptors
if (pluginBundle != null) {
URL installLoc = pluginBundle.getEntry("/"); //$NON-NLS-1$
try {
resolved = FileLocator.resolve(installLoc);
} catch (IOException e) {
e.printStackTrace();
}
}
if (resolved != null) {
if(resolved.getProtocol().equals("file")) {
try {
cpath.append(new File(resolved.toURI()).getAbsolutePath());
} catch (URISyntaxException e) {
e.printStackTrace();
}
cpath.append(File.separatorChar);
cpath.append(localPath);
} else {
throw new RuntimeException("Cannot handle protocol "+resolved.getProtocol());
}
}
// Verify that the file actually exists at the plugins location
// derived above. If not then it might be because we are inside
// a runtime workbench. Check under the workspace directory.
if (new File(cpath.toString()).exists()) {
// File does exist under the plugins directory
return cpath.toString();
} else {
throw new InternalError("File "+cpath+" does not exist.");
}
}
}