package com.redhat.ceylon.eclipse.core.launch; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.PROBLEM_MARKER_ID; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getCeylonModulesOutputFolder; import static com.redhat.ceylon.eclipse.core.builder.CeylonBuilder.getInterpolatedCeylonSystemRepo; import static com.redhat.ceylon.eclipse.core.launch.ICeylonLaunchConfigurationConstants.ATTR_LAUNCH_VERBOSE; import static com.redhat.ceylon.eclipse.core.launch.ICeylonLaunchConfigurationConstants.ATTR_MODULE_NAME; import static com.redhat.ceylon.eclipse.core.launch.ICeylonLaunchConfigurationConstants.ATTR_TOPLEVEL_NAME; import static com.redhat.ceylon.eclipse.core.launch.ICeylonLaunchConfigurationConstants.DEFAULT_RUN_MARKER; import static com.redhat.ceylon.eclipse.core.launch.ICeylonLaunchConfigurationConstants.ID_CEYLON_JAVASCRIPT_MODULE; import static com.redhat.ceylon.eclipse.core.launch.LaunchHelper.getStartLocation; import static com.redhat.ceylon.eclipse.util.CeylonHelper.toJavaStringList; import static com.redhat.ceylon.eclipse.util.InteropUtils.toJavaString; import static com.redhat.ceylon.eclipse.java2ceylon.Java2CeylonProxies.*; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; 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.Status; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.IDebugTarget; import org.eclipse.debug.core.model.IProcess; import org.eclipse.jdt.debug.core.IJavaDebugTarget; import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint; import org.eclipse.jdt.debug.core.JDIDebugModel; import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; import org.eclipse.jdt.internal.launching.LaunchingPlugin; import org.eclipse.jdt.internal.launching.StandardVMDebugger; import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.IVMRunner; import org.eclipse.jdt.launching.JavaLaunchDelegate; import org.eclipse.jdt.launching.VMRunnerConfiguration; import com.redhat.ceylon.common.Constants; import com.redhat.ceylon.common.Versions; import com.redhat.ceylon.eclipse.core.debug.model.CeylonJDIDebugTarget; import com.redhat.ceylon.eclipse.ui.CeylonPlugin; import com.redhat.ceylon.ide.common.model.CeylonIdeConfig; import com.redhat.ceylon.ide.common.model.CeylonProject; import com.sun.jdi.VirtualMachine; public class ModuleLaunchDelegate extends JavaLaunchDelegate { @Override public String verifyMainTypeName(ILaunchConfiguration configuration) throws CoreException { return "com.redhat.ceylon.launcher.Launcher"; } @Override public String getProgramArguments(ILaunchConfiguration configuration) throws CoreException { final List<IPath> workingRepos = new ArrayList<IPath>(); final IProject project = getJavaProject(configuration).getProject(); ArrayList<IProject> projects = new ArrayList<>(project.getReferencedProjects().length+1); projects.add(project); projects.addAll(Arrays.asList(project.getReferencedProjects())); for(IProject p : projects) { try {// projects may not exist in workspace IPath test = getCeylonModulesOutputFolder(p).getLocation(); workingRepos.add(test); } catch (Exception e) { continue; } } boolean runAsJs = DebugPlugin.getDefault().getLaunchManager() .getLaunchConfigurationType(ID_CEYLON_JAVASCRIPT_MODULE) .equals(configuration.getType()); List<String> newArgs = new ArrayList<String>(); prepareArguments(newArgs, workingRepos, project, configuration, runAsJs); List<String> args = Arrays.asList(DebugPlugin.parseArguments(super.getProgramArguments(configuration))); newArgs.addAll(args); return DebugPlugin.renderArguments(newArgs.toArray(new String[0]), null); } @Override public String getVMArguments(ILaunchConfiguration configuration) throws CoreException { IProject project = getJavaProject(configuration).getProject(); //user values at the end although JVMs behave differently List<String> vmArgs = new ArrayList<String>(); vmArgs.add("-Dceylon.system.version="+Versions.CEYLON_VERSION_NUMBER); vmArgs.add("-Dceylon.system.repo="+getInterpolatedCeylonSystemRepo(project)); File javaDebugAgentPath = CeylonPlugin.getInstance().getDebugAgentJar(); if (javaDebugAgentPath != null) { vmArgs.add("-javaagent:" + javaDebugAgentPath.getAbsolutePath()); } CeylonIdeConfig ideConfig = modelJ2C().ideConfig(project); if (ideConfig != null) { ceylon.language.String nodePath = ideConfig.getNodePath(); if (nodePath != null) { vmArgs.add("-D" + Constants.PROP_CEYLON_EXTCMD_NODE + "=" + nodePath.toString()); } } vmArgs.addAll(Arrays.asList(DebugPlugin.parseArguments(super.getVMArguments(configuration)))); return DebugPlugin.renderArguments(vmArgs.toArray(new String[0]), null); } @Override public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) throws CoreException { final IVMRunner runner = super.getVMRunner(configuration, mode); if (runner instanceof StandardVMDebugger) { IVMInstall vmInstall = getVMInstall(configuration); return new StandardVMDebugger(vmInstall){ @Override public void run(VMRunnerConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException { try { super.run(config, launch, monitor); } catch (final Exception e) { e.printStackTrace(); throw new CoreException(new Status(IStatus.ERROR, CeylonPlugin.PLUGIN_ID, "Ceylon Module Launcher Error", e)); } } @Override protected IDebugTarget createDebugTarget( final VMRunnerConfiguration config, final ILaunch launch, final int port, final IProcess process, final VirtualMachine vm) { final IDebugTarget[] target = new IDebugTarget[1]; IWorkspaceRunnable r = new IWorkspaceRunnable() { public void run(IProgressMonitor m) { target[0] = new CeylonJDIDebugTarget(launch, vm, renderDebugTarget(config.getClassToLaunch(), port), true, false, process, config.isResumeOnStartup()); } }; try { ResourcesPlugin.getWorkspace().run(r, null, 0, null); } catch (CoreException e) { JDIDebugPlugin.log(e); } return target[0]; } }; } else { return runner; } } protected void prepareArguments(List<String> args, List<IPath> workingRepos, IProject project, ILaunchConfiguration configuration, boolean runAsJs) throws CoreException { if (runAsJs) { args.add("run-js"); } else { args.add("run"); } CeylonProject<IProject,IResource,IFolder,IFile> ceylonProject = modelJ2C().ceylonModel().getProject(project); prepareRepositoryArguments(args, ceylonProject, workingRepos); prepareOverridesArgument(args, ceylonProject); prepareFlatClasspathArgument(args, ceylonProject); prepareAutoExportMavenDependencies(args, ceylonProject); prepareFullyExportMavenDependencies(args, ceylonProject); prepareOfflineArgument(args, ceylonProject); if (configuration.getAttribute(ATTR_LAUNCH_VERBOSE, false)) { prepareVerboseArgument(args, runAsJs); } String topLevel = configuration.getAttribute(ATTR_TOPLEVEL_NAME, ""); int def = topLevel.indexOf(DEFAULT_RUN_MARKER); if (def != -1) { topLevel = topLevel.substring(0, def); } if (!"".equals(topLevel) && def == -1) { // default run not found args.add("--run"); args.add(topLevel); } args.add("--"); args.add(configuration.getAttribute(ATTR_MODULE_NAME, "")); } protected void prepareRepositoryArguments(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project, List<IPath> workingRepos) { for (IPath repo : workingRepos) { args.add("--rep"); args.add(repo.toOSString()); } for (String repo: toJavaStringList(project.getConfiguration() .getProjectLocalRepos())) { args.add("--rep"); args.add(repo); } } protected void prepareOverridesArgument(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project) { String overrides = toJavaString(project.getConfiguration().getOverrides()); if (overrides != null) { args.add("--overrides=" + overrides); } } protected void prepareFlatClasspathArgument(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project) { boolean flatClasspath = project.getConfiguration().getFlatClasspath(); if (flatClasspath) { args.add("--flat-classpath"); } } protected void prepareAutoExportMavenDependencies(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project) { boolean autoExportMavenDependencies = project.getConfiguration().getAutoExportMavenDependencies(); if (autoExportMavenDependencies) { args.add("--auto-export-maven-dependencies"); } } protected void prepareFullyExportMavenDependencies(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project) { boolean fullyExportMavenDependencies = project.getConfiguration().getFullyExportMavenDependencies(); if (fullyExportMavenDependencies) { args.add("--fully-export-maven-dependencies"); } } protected void prepareOfflineArgument(List<String> args, CeylonProject<IProject,IResource,IFolder,IFile> project) { if (project.getConfiguration().getOffline()) { args.add("--offline"); } } protected void prepareVerboseArgument(List<String> args, boolean runAsJs) { args.add("--verbose"); if (runAsJs) { args.add("--debug"); args.add("debug"); // } } @Override public String[] getClasspath(ILaunchConfiguration configuration) throws CoreException { List<String> classpathList = new ArrayList<String>(); // at runtime, we just need ceylon-bootstrap; everything else should be from the system repo classpathList.addAll(CeylonPlugin.getModuleLauncherJars()); return classpathList.toArray(new String[classpathList.size()]); } @Override protected boolean isLaunchProblem(IMarker problemMarker) throws CoreException { if (super.isLaunchProblem(problemMarker)) { return true; } if (!problemMarker.getType().equals(PROBLEM_MARKER_ID)) { return false; } Integer severity = (Integer) problemMarker.getAttribute(IMarker.SEVERITY); if (severity!=null) { return severity.intValue()>=IMarker.SEVERITY_ERROR; } return false; } @Override public void handleDebugEvents(DebugEvent[] events) { for (int i = 0; i < events.length; i++) { DebugEvent event = events[i]; if (event.getKind() == DebugEvent.CREATE && event.getSource() instanceof IJavaDebugTarget) { IJavaDebugTarget target = (IJavaDebugTarget) event.getSource(); ILaunch launch = target.getLaunch(); if (launch != null) { ILaunchConfiguration configuration = launch .getLaunchConfiguration(); if (configuration != null) { try { if (isStopInMain(configuration)) { String location=getStartLocation(configuration); String type = null; String method = null; if (location != null) { String[] parts = location.split("/"); type = parts[0]; if (parts.length > 1) method = parts[1]; } if (type != null) { Map<String, Object> map = new HashMap<String, Object>(); map .put( IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN, IJavaLaunchConfigurationConstants.ATTR_STOP_IN_MAIN); IJavaMethodBreakpoint bp = JDIDebugModel .createMethodBreakpoint( ResourcesPlugin .getWorkspace() .getRoot(), type, method, //$NON-NLS-1$ "()V", true, false, false, -1, -1, -1, 1, false, map); bp.setPersisted(false); target.breakpointAdded(bp); DebugPlugin.getDefault() .removeDebugEventListener(this); } } } catch (CoreException e) { LaunchingPlugin.log(e); } } } } } } }