/******************************************************************************* * Copyright (c) 2013 GoPivotal, Inc. * 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: * GoPivotal, Inc. - initial API and implementation *******************************************************************************/ package org.springframework.ide.eclipse.boot.launch; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationType; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.debug.ui.launchConfigurations.JavaApplicationLaunchShortcut; import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; import org.eclipse.jdt.internal.debug.ui.launcher.LauncherMessages; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.StructuredSelection; import org.springframework.ide.eclipse.boot.core.BootActivator; import org.springsource.ide.eclipse.commons.frameworks.core.ExceptionUtil; import org.springsource.ide.eclipse.commons.frameworks.core.maintype.MainTypeFinder; @SuppressWarnings("restriction") public class BootLaunchShortcut extends JavaApplicationLaunchShortcut { /** * Launch configuration id of the configs created by this shortcut. */ public static final String LAUNCH_CONFIG_TYPE_ID = BootLaunchConfigurationDelegate.TYPE_ID; @Override public IType[] findTypes(Object[] elements, IRunnableContext context) throws InterruptedException, CoreException { //For spring boot app, instead of searching for a main type in the entire project and all its // libraries... try to look inside the project's pom for the corresponding property. for (Object e : elements) { if (e instanceof IProject) { try { e = JavaCore.create((IProject)e); } catch (Throwable ignore) { } } { IType type = isMainMethod(elements[0]); if(type != null) { return new IType[] {type}; } } if (e instanceof IJavaElement) { if (e instanceof IType) { if (hasMainMethod((IType) e)) { return new IType[] {(IType)e}; } } if (e instanceof ICompilationUnit) { for (IType t : ((ICompilationUnit) e).getAllTypes()) { if (hasMainMethod(t)) { return new IType[] {t}; } } } final IJavaProject jp = ((IJavaElement)e).getJavaProject(); final IType[][] result = new IType[][] { null }; try { context.run(/*fork*/false, /*true*/false, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { result[0] = MainTypeFinder.guessMainTypes(jp, monitor); } catch (CoreException e) { throw new InvocationTargetException(e); } } }); } catch (InvocationTargetException exception) { throw ExceptionUtil.coreException(exception); } return result[0]; } } //This isn't the best thing to to do as it searches also in all the library jars for main types. But it is // only a fallback option if the above code failed. (Or should we rather signal an error instead?) return super.findTypes(elements, context); } private boolean hasMainMethod(IType t) { try { for (IMethod m : t.getMethods()) { if (m.isMainMethod()) { return true; } } } catch (Exception e) { BootActivator.log(e); } return false; } /** * Returns the smallest enclosing <code>IType</code> if the specified object is a main method, or <code>null</code> * @param o the object to inspect * @return the smallest enclosing <code>IType</code> of the specified object if it is a main method or <code>null</code> if it is not */ private IType isMainMethod(Object o) { if(o instanceof IAdaptable) { IAdaptable adapt = (IAdaptable) o; IJavaElement element = (IJavaElement) adapt.getAdapter(IJavaElement.class); if(element != null && element.getElementType() == IJavaElement.METHOD) { try { IMethod method = (IMethod) element; if(method.isMainMethod()) { return method.getDeclaringType(); } } catch (JavaModelException jme) {JDIDebugUIPlugin.log(jme);} } } return null; } @Override protected ILaunchConfigurationType getConfigurationType() { return getLaunchManager().getLaunchConfigurationType(LAUNCH_CONFIG_TYPE_ID); } /** * Overridden, copied and changed to alter the generated launch configuration name. */ @Override public ILaunchConfiguration createConfiguration(IType type) { ILaunchConfiguration config = null; try { config = BootLaunchConfigurationDelegate.createConf(type); } catch (CoreException exception) { MessageDialog.openError(JDIDebugUIPlugin.getActiveWorkbenchShell(), LauncherMessages.JavaLaunchShortcut_3, exception.getStatus().getMessage()); } return config; } /** * Returns the singleton launch manager. * * @return launch manager */ private ILaunchManager getLaunchManager() { return DebugPlugin.getDefault().getLaunchManager(); } public static void launch(IProject project, String mode) { BootLaunchShortcut shortcut = new BootLaunchShortcut(); StructuredSelection selection = new StructuredSelection(new Object[] {project}); shortcut.launch(selection, mode); } }