# HG changeset patch # Parent 90cdb5ae8c40d263c3f74b9a370d92120ae29344 # User Jesse Glick #71515: API for blocking project actions. diff --git a/ant.freeform/nbproject/project.xml b/ant.freeform/nbproject/project.xml --- a/ant.freeform/nbproject/project.xml +++ b/ant.freeform/nbproject/project.xml @@ -82,7 +82,7 @@ 1 - 1.31 + 1.43 diff --git a/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java b/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java --- a/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java +++ b/ant.freeform/src/org/netbeans/modules/ant/freeform/Actions.java @@ -72,7 +72,9 @@ import javax.swing.JSeparator; import org.apache.tools.ant.module.api.support.ActionUtils; import org.netbeans.api.project.ProjectManager; +import org.netbeans.modules.ant.freeform.ui.TargetMappingPanel; import org.netbeans.modules.ant.freeform.ui.UnboundTargetAlert; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.SingleMethod; import org.netbeans.spi.project.support.ant.AntProjectHelper; @@ -85,6 +87,7 @@ import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; import org.openide.awt.DynamicMenuContent; +import org.openide.execution.ExecutorTask; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; @@ -92,6 +95,8 @@ import org.openide.util.Lookup; import org.openide.util.Mutex; import org.openide.util.NbBundle; +import org.openide.util.Task; +import org.openide.util.TaskListener; import org.openide.util.Union2; import org.openide.util.actions.Presenter; import org.openide.xml.XMLUtil; @@ -479,7 +484,7 @@ // Run default target. targetNameArray = null; } - TARGET_RUNNER.runTarget(scriptFile.first(), targetNameArray, props); + TARGET_RUNNER.runTarget(scriptFile.first(), targetNameArray, props, ActionProgress.start(context)); } else { assert scriptFile.hasSecond(); //#57011: if the script does not exist, show a warning: @@ -618,11 +623,16 @@ static class TargetRunner { public TargetRunner() {} - public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props) { + public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props, final ActionProgress listener) { try { - ActionUtils.runTarget(scriptFile, targetNameArray, props); + ActionUtils.runTarget(scriptFile, targetNameArray, props).addTaskListener(new TaskListener() { + @Override public void taskFinished(Task task) { + listener.finished(((ExecutorTask) task).result() == 0); + } + }); } catch (IOException e) { ErrorManager.getDefault().notify(e); + listener.finished(false); } } } diff --git a/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/ActionsTest.java b/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/ActionsTest.java --- a/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/ActionsTest.java +++ b/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/ActionsTest.java @@ -56,6 +56,7 @@ import java.util.TreeSet; import javax.swing.Action; import org.netbeans.api.project.Project; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ui.LogicalViewProvider; import org.openide.filesystems.FileObject; @@ -116,7 +117,7 @@ static { Actions.TARGET_RUNNER = new Actions.TargetRunner() { - public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props) { + public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props, ActionProgress listener) { targetsRun.add(new AntTargetInvocation(scriptFile, targetNameArray, NbCollections.checkedMapByFilter(props, String.class, String.class, true))); } diff --git a/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/LookupMergerImplTest.java b/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/LookupMergerImplTest.java --- a/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/LookupMergerImplTest.java +++ b/ant.freeform/test/unit/src/org/netbeans/modules/ant/freeform/LookupMergerImplTest.java @@ -52,6 +52,7 @@ import java.util.TreeMap; import org.netbeans.api.project.ProjectManager; import org.netbeans.junit.NbTestCase; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.support.ant.AntProjectHelper; import org.openide.filesystems.FileObject; @@ -70,7 +71,7 @@ private static List targetsRun = new ArrayList(); static { Actions.TARGET_RUNNER = new Actions.TargetRunner() { - public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props) { + public void runTarget(FileObject scriptFile, String[] targetNameArray, Properties props, ActionProgress listener) { targetsRun.add(scriptFile.getNameExt() + ":" + Arrays.toString(targetNameArray) + ":" + new TreeMap(props)); } }; diff --git a/apisupport.ant/nbproject/project.xml b/apisupport.ant/nbproject/project.xml --- a/apisupport.ant/nbproject/project.xml +++ b/apisupport.ant/nbproject/project.xml @@ -202,7 +202,7 @@ 1 - 1.35 + 1.43 diff --git a/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/ModuleActions.java b/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/ModuleActions.java --- a/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/ModuleActions.java +++ b/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/ModuleActions.java @@ -56,6 +56,7 @@ import java.util.Map.Entry; import java.util.Properties; import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Pattern; import javax.lang.model.element.TypeElement; import javax.swing.Action; @@ -85,6 +86,7 @@ import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils; import org.netbeans.modules.apisupport.project.universe.HarnessVersion; import org.netbeans.modules.apisupport.project.universe.NbPlatform; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.SingleMethod; import org.netbeans.spi.project.support.ant.AntProjectHelper; @@ -100,6 +102,7 @@ import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionRegistration; +import org.openide.execution.ExecutorTask; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; @@ -108,6 +111,7 @@ import org.openide.util.NbBundle.Messages; import org.openide.util.RequestProcessor; import org.openide.util.Task; +import org.openide.util.TaskListener; import org.openide.util.lookup.Lookups; public final class ModuleActions implements ActionProvider, ExecProject { @@ -367,8 +371,26 @@ return; } + // XXX prefer to call just if and when actually starting target, but that is hard to calculate here + final ActionProgress listener = ActionProgress.start(context); Runnable runnable = new Runnable() { - public void run() { + ExecutorTask task; + @Override public void run() { + try { + doRun(); + } finally { + if (task != null) { + task.addTaskListener(new TaskListener() { + @Override public void taskFinished(Task _) { + listener.finished(task.result() == 0); + } + }); + } else { + listener.finished(false); + } + } + } + void doRun() { Properties p = new Properties(); String[] targetNames; if (command.equals(COMMAND_COMPILE_SINGLE)) { @@ -402,7 +424,9 @@ // if ( Boolean.parseBoolean(enableQuickTest) // && "unit".equals(testSources.testType) // NOI18N // && !hasTestUnitDataDir()) { // NOI18N -// if (bypassAntBuildScript(command, testSources.sources)) { +// AtomicReference _task = new AtomicReference(); +// if (bypassAntBuildScript(command, testSources.sources, _task)) { +// task = _task.get(); // return ; // } // } @@ -472,6 +496,7 @@ } } try { + task = ActionUtils.runTarget(findBuildXml(project), targetNames, p); } catch (IOException e) { Util.err.notify(e); @@ -619,7 +644,7 @@ return new String[] {"debug-test-single-nb"}; // NOI18N } - private boolean bypassAntBuildScript(String command, FileObject[] files) throws IllegalArgumentException { + private boolean bypassAntBuildScript(String command, FileObject[] files, AtomicReference task) throws IllegalArgumentException { FileObject toRun = null; if (COMMAND_RUN_SINGLE.equals(command) || COMMAND_DEBUG_SINGLE.equals(command)) { @@ -638,7 +663,7 @@ properties.put(JavaRunner.PROP_EXECUTE_FILE, toRun); - JavaRunner.execute(commandToExecute, properties); + task.set(JavaRunner.execute(commandToExecute, properties)); } catch (IOException ex) { Exceptions.printStackTrace(ex); } diff --git a/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/SuiteActions.java b/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/SuiteActions.java --- a/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/SuiteActions.java +++ b/apisupport.ant/src/org/netbeans/modules/apisupport/project/ui/SuiteActions.java @@ -59,6 +59,7 @@ import javax.swing.JMenu; import javax.swing.JMenuItem; import org.apache.tools.ant.module.api.support.ActionUtils; +import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.project.Project; import org.netbeans.modules.apisupport.project.NbModuleProject; import org.netbeans.modules.apisupport.project.api.BrandingUtils; @@ -73,6 +74,7 @@ import org.netbeans.modules.apisupport.project.ui.customizer.SuiteUtils; import org.netbeans.modules.apisupport.project.universe.HarnessVersion; import org.netbeans.modules.apisupport.project.universe.NbPlatform; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.support.ant.AntProjectHelper; @@ -92,6 +94,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.Task; +import org.openide.util.TaskListener; import org.openide.util.actions.Presenter; /** @@ -395,24 +398,18 @@ } } ExecutorTask task = null; - ActionEvent ev; try { task = invokeActionImpl(command, context); } catch (IOException e) { Util.err.notify(e); } - if ( - task != null && - (ev = context.lookup(ActionEvent.class)) != null && - "waitFinished".equals(ev.getActionCommand()) // NOI18N - ) { - task.waitFinished(); - if (ev.getSource() instanceof ExecutorTask[]) { - ExecutorTask[] arr = (ExecutorTask[])ev.getSource(); - if (arr.length > 0) { - arr[0] = task; + if (task != null) { + final ActionProgress listener = ActionProgress.start(context); + task.addTaskListener(new TaskListener() { + @Override public void taskFinished(Task task) { + listener.finished(((ExecutorTask) task).result() == 0); } - } + }); } } } @@ -420,7 +417,7 @@ /** Used from tests to start the build script and get task that allows to track its progress. * @return null or task that was started */ - public ExecutorTask invokeActionImpl(String command, Lookup context) throws IllegalArgumentException, IOException { + public @CheckForNull ExecutorTask invokeActionImpl(String command, Lookup context) throws IllegalArgumentException, IOException { String[] targetNames; Properties p = new Properties(); diff --git a/apisupport.ant/test/unit/src/org/netbeans/modules/apisupport/project/suite/BuildZipDistributionTest.java b/apisupport.ant/test/unit/src/org/netbeans/modules/apisupport/project/suite/BuildZipDistributionTest.java --- a/apisupport.ant/test/unit/src/org/netbeans/modules/apisupport/project/suite/BuildZipDistributionTest.java +++ b/apisupport.ant/test/unit/src/org/netbeans/modules/apisupport/project/suite/BuildZipDistributionTest.java @@ -44,7 +44,6 @@ package org.netbeans.modules.apisupport.project.suite; -import java.awt.event.ActionEvent; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; @@ -75,8 +74,6 @@ import org.openide.filesystems.FileUtil; import org.openide.util.NbCollections; import org.openide.util.Utilities; -import org.openide.util.lookup.Lookups; -import org.openide.util.lookup.ProxyLookup; /** * Checks building of ZIP support. @@ -156,13 +153,9 @@ DialogDisplayerImpl.returnFromNotify(DialogDescriptor.NO_OPTION); - ExecutorTask[] taskHolder = new ExecutorTask[1]; - ActionEvent ev = new ActionEvent(taskHolder, 0, "waitFinished"); // NOI18N - ProxyLookup lkp = new ProxyLookup(suite.getLookup(), Lookups.singleton(ev)); - p.invokeAction("build-zip", lkp); - assertNotNull("Task was started", taskHolder[0]); - assertTrue("Finished already", taskHolder[0].isFinished()); - assertEquals("Finished ok", 0, taskHolder[0].result()); + ExecutorTask task = p.invokeActionImpl("build-zip", suite.getLookup()); + assertNotNull("Task was started", task); + assertEquals("Finished ok", 0, task.result()); FileObject[] arr = suite.getProjectDirectory().getChildren(); List subobj = new ArrayList(Arrays.asList(arr)); diff --git a/coherence/nbproject/project.xml b/coherence/nbproject/project.xml --- a/coherence/nbproject/project.xml +++ b/coherence/nbproject/project.xml @@ -6,15 +6,6 @@ org.netbeans.modules.coherence - org.apache.tools.ant.module - - - - 3 - 3.52 - - - org.jdesktop.beansbinding @@ -162,7 +153,7 @@ 1 - 1.41 + 1.43 @@ -228,14 +219,6 @@ - org.openide.actions - - - - 6.16.1 - - - org.openide.awt @@ -252,14 +235,6 @@ - org.openide.execution - - - - 1.25 - - - org.openide.explorer @@ -276,14 +251,6 @@ - org.openide.io - - - - 1.23.1 - - - org.openide.loaders @@ -296,7 +263,7 @@ - 7.16.1 + 7.23 diff --git a/coherence/src/org/netbeans/modules/coherence/project/actions/RunOnCoherence.java b/coherence/src/org/netbeans/modules/coherence/project/actions/RunOnCoherence.java --- a/coherence/src/org/netbeans/modules/coherence/project/actions/RunOnCoherence.java +++ b/coherence/src/org/netbeans/modules/coherence/project/actions/RunOnCoherence.java @@ -43,15 +43,15 @@ import java.awt.event.ActionEvent; import java.io.File; -import java.io.IOException; import java.net.URI; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.logging.Level; +import java.util.logging.Logger; import javax.swing.AbstractAction; import javax.swing.Action; -import org.apache.tools.ant.module.api.support.ActionUtils; import org.netbeans.api.java.project.JavaProjectConstants; import org.netbeans.api.project.Project; import org.netbeans.api.project.ant.AntArtifact; @@ -60,18 +60,18 @@ import org.netbeans.modules.coherence.server.CoherenceInstance; import org.netbeans.modules.coherence.server.CoherenceInstanceProvider; import org.netbeans.modules.coherence.server.util.ClasspathPropertyUtils; -import org.netbeans.spi.project.support.ant.GeneratedFilesHelper; +import org.netbeans.spi.project.ActionProgress; +import org.netbeans.spi.project.ActionProvider; import org.openide.awt.ActionID; import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; import org.openide.awt.DynamicMenuContent; -import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.ContextAwareAction; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.NbBundle; +import org.openide.util.lookup.Lookups; @ActionID(id="org.netbeans.modules.coherence.project.actions.RunOnCoherence", category="Project") @ActionRegistration(displayName="#LBL_RunOnCoherence", lazy=false) @@ -82,6 +82,8 @@ }) public class RunOnCoherence extends AbstractAction implements ContextAwareAction { + private static final Logger LOG = Logger.getLogger(RunOnCoherence.class.getName()); + @Override public void actionPerformed(ActionEvent e) { assert false; @@ -112,40 +114,30 @@ if (artifactLocs.length > 0) { URI jarLocation = artifactLocs[0]; File baseJar = new File(FileUtil.toFile(project.getProjectDirectory()), jarLocation.toString()); - List relatedInstances = getRelatedInstances(baseJar.getAbsolutePath()); -// ActionProvider ap = project.getLookup().lookup(ActionProvider.class); - - // Should be replaced by some blocking method of ActionProvider once - // similar method will be introduced there. See issue #71515. - AtomicBoolean targetResult = new AtomicBoolean(false); - try { - Properties properties = new Properties(); - org.openide.execution.ExecutorTask runTarget = ActionUtils.runTarget( - getBuildXml(project), - new String[] {"jar"}, //NOI18N - properties); - if (runTarget.result() == 0) { - targetResult.set(true); - } - } catch (IOException ex) { - Exceptions.printStackTrace(ex); - } catch (IllegalArgumentException ex) { - Exceptions.printStackTrace(ex); - } - - if (targetResult.get()) { - for (CoherenceInstance coherenceInstance : relatedInstances) { - coherenceInstance.getServer().restart(); + final List relatedInstances = getRelatedInstances(baseJar.getAbsolutePath()); + ActionProvider ap = project.getLookup().lookup(ActionProvider.class); + if (ap != null && Arrays.asList(ap.getSupportedActions()).contains(ActionProvider.COMMAND_BUILD) && ap.isActionEnabled(ActionProvider.COMMAND_BUILD, Lookup.EMPTY)) { + final AtomicBoolean started = new AtomicBoolean(); + ap.invokeAction(ActionProvider.COMMAND_BUILD, Lookups.singleton(new ActionProgress() { + @Override public void started() { + started.set(true); + } + @Override public void finished(boolean success) { + if (success) { + for (CoherenceInstance coherenceInstance : relatedInstances) { + coherenceInstance.getServer().restart(); + } + } + } + })); + if (!started.get()) { + LOG.log(Level.WARNING, "ActionProgress not supported by {0}", project); } } } } } - private static FileObject getBuildXml(Project project) { - return project.getProjectDirectory().getFileObject(GeneratedFilesHelper.BUILD_XML_PATH); - } - private static List getRelatedInstances(String location) { List related = new ArrayList(); List allinstances = CoherenceInstanceProvider.getCoherenceProvider().getCoherenceInstances(); diff --git a/j2ee.earproject/nbproject/project.xml b/j2ee.earproject/nbproject/project.xml --- a/j2ee.earproject/nbproject/project.xml +++ b/j2ee.earproject/nbproject/project.xml @@ -231,7 +231,7 @@ 1 - 1.12 + 1.43 diff --git a/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarActionProvider.java b/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarActionProvider.java --- a/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarActionProvider.java +++ b/j2ee.earproject/src/org/netbeans/modules/j2ee/earproject/EarActionProvider.java @@ -54,7 +54,6 @@ import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.api.debugger.Session; import org.netbeans.api.debugger.jpda.AttachingDICookie; -import org.netbeans.api.j2ee.core.Profile; import org.netbeans.api.project.Project; import org.netbeans.modules.j2ee.api.ejbjar.EjbProjectConstants; import org.netbeans.modules.j2ee.common.project.ui.DeployOnSaveUtils; @@ -70,11 +69,13 @@ import org.netbeans.modules.java.api.common.ant.UpdateHelper; import org.netbeans.modules.web.api.webmodule.WebModule; import org.netbeans.modules.web.spi.webmodule.WebModuleProvider; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.SubprojectProvider; import org.netbeans.spi.project.ui.support.DefaultProjectOperations; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; +import org.openide.execution.ExecutorTask; import org.openide.filesystems.FileObject; import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; @@ -182,8 +183,6 @@ } final String commandToExecute = realCommand; - Runnable action = new Runnable () { - public void run () { Properties p = new Properties(); String[] targetNames; @@ -198,6 +197,7 @@ p = null; } final J2eeApplicationProvider app = EarActionProvider.this.project.getAppModule(); + final ActionProgress listener = ActionProgress.start(context); try { Deployment.getDefault().suspendDeployOnSave(app); ActionUtils.runTarget(findBuildXml(), targetNames, p).addTaskListener(new TaskListener() { @@ -205,19 +205,18 @@ @Override public void taskFinished(Task task) { Deployment.getDefault().resumeDeployOnSave(app); + listener.finished(((ExecutorTask) task).result() == 0); } }); } catch (IOException e) { Deployment.getDefault().resumeDeployOnSave(app); Exceptions.printStackTrace(e); + listener.finished(false); } catch (RuntimeException ex) { Deployment.getDefault().resumeDeployOnSave(app); + listener.finished(false); throw ex; } - } - }; - - action.run(); } /** diff --git a/java.api.common/nbproject/project.xml b/java.api.common/nbproject/project.xml --- a/java.api.common/nbproject/project.xml +++ b/java.api.common/nbproject/project.xml @@ -126,7 +126,7 @@ 1 - 1.14 + 1.43 diff --git a/java.api.common/src/org/netbeans/modules/java/api/common/project/BaseActionProvider.java b/java.api.common/src/org/netbeans/modules/java/api/common/project/BaseActionProvider.java --- a/java.api.common/src/org/netbeans/modules/java/api/common/project/BaseActionProvider.java +++ b/java.api.common/src/org/netbeans/modules/java/api/common/project/BaseActionProvider.java @@ -114,6 +114,7 @@ import org.netbeans.modules.java.api.common.util.CommonProjectUtils; import org.netbeans.spi.java.classpath.ClassPathProvider; import org.netbeans.spi.java.classpath.support.ClassPathSupport; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ProjectConfiguration; import org.netbeans.spi.project.SingleMethod; @@ -406,6 +407,8 @@ final boolean isCompileOnSaveEnabled = isCompileOnSaveEnabled(); final AtomicReference caller = new AtomicReference(Thread.currentThread()); final AtomicBoolean called = new AtomicBoolean(false); + // XXX prefer to call just if and when actually starting target, but that is hard to calculate here + final ActionProgress listener = ActionProgress.start(context); class Action implements Runnable { @@ -418,6 +421,7 @@ * the default values (possibly incorrect) are used. */ private boolean doJavaChecks = true; + ExecutorTask task; @Override public void run () { @@ -425,6 +429,23 @@ return; } called.set(true); + try { + doRun(); + } finally { + if (task != null) { + task.addTaskListener(new TaskListener() { + @org.netbeans.api.annotations.common.SuppressWarnings("UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR") + @Override public void taskFinished(Task _) { + listener.finished(task.result() == 0); + } + }); + } else { + listener.finished(false); + } + } + } + + void doRun() { Properties p = new Properties(); String[] targetNames; @@ -465,6 +486,7 @@ execProperties.put("applet.url", url); execProperties.put(JavaRunner.PROP_EXECUTE_FILE, file); prepareSystemProperties(execProperties, false); + task = JavaRunner.execute(targetNames[0], execProperties); } } catch (IOException ex) { @@ -474,7 +496,9 @@ } if (!isServerExecution() && (COMMAND_RUN.equals(command) || COMMAND_DEBUG.equals(command) || COMMAND_DEBUG_STEP_INTO.equals(command))) { prepareSystemProperties(execProperties, false); - bypassAntBuildScript(command, context, execProperties); + AtomicReference _task = new AtomicReference(); + bypassAntBuildScript(command, context, execProperties, _task); + task = _task.get(); return ; } // for example RUN_SINGLE Java file with Servlet must be run on server and not locally @@ -487,7 +511,9 @@ } else { execProperties.put(JavaRunner.PROP_CLASSNAME, p.getProperty("debug.class")); } - bypassAntBuildScript(command, context, execProperties); + AtomicReference _task = new AtomicReference(); + bypassAntBuildScript(command, context, execProperties, _task); + task = _task.get(); return; } if (COMMAND_TEST_SINGLE.equals(command) || COMMAND_DEBUG_TEST_SINGLE.equals(command)) { @@ -497,6 +523,7 @@ execProperties.put(JavaRunner.PROP_EXECUTE_FILE, files[0]); execProperties.put("tmp.dir", updateHelper.getAntProjectHelper().resolvePath(evaluator.getProperty(ProjectProperties.BUILD_DIR))); //NOI18N updateJavaRunnerClasspath(command, execProperties); + task = JavaRunner.execute(COMMAND_TEST_SINGLE.equals(command) ? JavaRunner.QUICK_TEST : JavaRunner.QUICK_TEST_DEBUG, execProperties); } catch (IOException ex) { Exceptions.printStackTrace(ex); @@ -510,6 +537,7 @@ execProperties.put(JavaRunner.PROP_EXECUTE_FILE, methodSpec.getFile()); execProperties.put("tmp.dir",updateHelper.getAntProjectHelper().resolvePath(evaluator.getProperty(ProjectProperties.BUILD_DIR))); //NOI18N updateJavaRunnerClasspath(command, execProperties); + task = JavaRunner.execute(command.equals(SingleMethod.COMMAND_RUN_SINGLE_METHOD) ? JavaRunner.QUICK_TEST : JavaRunner.QUICK_TEST_DEBUG, execProperties); } catch (IOException ex) { @@ -547,7 +575,8 @@ cb2.antTargetInvocationStarted(command, context); } try { - ActionUtils.runTarget(buildFo, targetNames, p).addTaskListener(new TaskListener() { + task = ActionUtils.runTarget(buildFo, targetNames, p); + task.addTaskListener(new TaskListener() { @Override public void taskFinished(Task task) { try { @@ -1352,7 +1381,7 @@ return srcDir; } - private void bypassAntBuildScript(String command, Lookup context, Map p) throws IllegalArgumentException { + private void bypassAntBuildScript(String command, Lookup context, Map p, AtomicReference task) throws IllegalArgumentException { boolean run = true; boolean hasMainMethod = true; @@ -1386,12 +1415,12 @@ updateJavaRunnerClasspath(command, p); if (run) { copyMultiValue(ProjectProperties.APPLICATION_ARGS, p); - JavaRunner.execute(debug ? JavaRunner.QUICK_DEBUG : JavaRunner.QUICK_RUN, p); + task.set(JavaRunner.execute(debug ? JavaRunner.QUICK_DEBUG : JavaRunner.QUICK_RUN, p)); } else { if (hasMainMethod) { - JavaRunner.execute(debug ? JavaRunner.QUICK_DEBUG : JavaRunner.QUICK_RUN, p); + task.set(JavaRunner.execute(debug ? JavaRunner.QUICK_DEBUG : JavaRunner.QUICK_RUN, p)); } else { - JavaRunner.execute(debug ? JavaRunner.QUICK_TEST_DEBUG : JavaRunner.QUICK_TEST, p); + task.set(JavaRunner.execute(debug ? JavaRunner.QUICK_TEST_DEBUG : JavaRunner.QUICK_TEST, p)); } } } catch (IOException ex) { diff --git a/javafx2.project/nbproject/project.xml b/javafx2.project/nbproject/project.xml --- a/javafx2.project/nbproject/project.xml +++ b/javafx2.project/nbproject/project.xml @@ -143,7 +143,7 @@ 1 - 1.34 + 1.43 diff --git a/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXActionProvider.java b/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXActionProvider.java --- a/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXActionProvider.java +++ b/javafx2.project/src/org/netbeans/modules/javafx2/project/JFXActionProvider.java @@ -44,21 +44,24 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.Properties; import org.apache.tools.ant.module.api.support.ActionUtils; import org.netbeans.api.annotations.common.CheckForNull; import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.project.Project; import org.netbeans.modules.java.j2seproject.api.J2SEPropertyEvaluator; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.LookupProvider; import org.netbeans.spi.project.ProjectServiceProvider; import org.netbeans.spi.project.support.ant.GeneratedFilesHelper; import org.netbeans.spi.project.support.ant.PropertyEvaluator; +import org.openide.execution.ExecutorTask; import org.openide.filesystems.FileObject; import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.openide.util.Parameters; +import org.openide.util.Task; +import org.openide.util.TaskListener; /** * Skeleton of JFX Action Provider @@ -90,32 +93,33 @@ @Override public void invokeAction(@NonNull String command, @NonNull Lookup context) throws IllegalArgumentException { - String target; - if ((target=(command))!=null) { + if (command != null) { FileObject buildFo = findBuildXml(); assert buildFo != null && buildFo.isValid(); String runAs = JFXProjectUtils.getFXProjectRunAs(prj); if(runAs == null) { runAs = JFXProjectProperties.RunAsType.STANDALONE.getString(); } + final ActionProgress listener = ActionProgress.start(context); try { + String target; if(runAs.equalsIgnoreCase(JFXProjectProperties.RunAsType.STANDALONE.getString())) { target = "jfxsa-".concat(command); //NOI18N - final Properties p = new Properties(); - ActionUtils.runTarget(buildFo, new String[] {target}, p); //NOI18N } else { if(runAs.equalsIgnoreCase(JFXProjectProperties.RunAsType.ASWEBSTART.getString())) { target = "jfxws-".concat(command); //NOI18N - final Properties p = new Properties(); - ActionUtils.runTarget(buildFo, new String[] {target}, p); //NOI18N } else { //JFXProjectProperties.RunAsType.INBROWSER target = "jfxbe-".concat(command); //NOI18N - final Properties p = new Properties(); - ActionUtils.runTarget(buildFo, new String[] {target}, p); //NOI18N } } + ActionUtils.runTarget(buildFo, new String[] {target}, null).addTaskListener(new TaskListener() { + @Override public void taskFinished(Task task) { + listener.finished(((ExecutorTask) task).result() == 0); + } + }); } catch (IOException ex) { Exceptions.printStackTrace(ex); + listener.finished(false); } } else { throw new IllegalArgumentException(command); diff --git a/javawebstart/nbproject/project.xml b/javawebstart/nbproject/project.xml --- a/javawebstart/nbproject/project.xml +++ b/javawebstart/nbproject/project.xml @@ -143,7 +143,7 @@ 1 - 1.12 + 1.43 diff --git a/javawebstart/src/org/netbeans/modules/javawebstart/RunJavaws.java b/javawebstart/src/org/netbeans/modules/javawebstart/RunJavaws.java --- a/javawebstart/src/org/netbeans/modules/javawebstart/RunJavaws.java +++ b/javawebstart/src/org/netbeans/modules/javawebstart/RunJavaws.java @@ -41,11 +41,13 @@ import java.io.IOException; import java.util.Collection; import org.netbeans.api.java.platform.JavaPlatform; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.openide.filesystems.FileUtil; import org.openide.loaders.DataObject; import org.openide.util.Exceptions; import org.openide.util.Lookup; +import org.openide.util.RequestProcessor; import org.openide.util.lookup.ServiceProvider; /** @@ -54,6 +56,8 @@ @ServiceProvider(service=ActionProvider.class) public class RunJavaws implements ActionProvider { + private static final RequestProcessor RP = new RequestProcessor(RunJavaws.class.getName(), Integer.MAX_VALUE); + @Override public String[] getSupportedActions() { return new String[] {COMMAND_RUN_SINGLE}; } @@ -65,11 +69,23 @@ } @Override public void invokeAction(String command, Lookup context) throws IllegalArgumentException { + final ActionProgress listener = ActionProgress.start(context); try { + final Process p = new ProcessBuilder(FileUtil.toFile(JavaPlatform.getDefault().findTool("javaws")).getAbsolutePath(), context.lookup(DataObject.class).getPrimaryFile().getURL().toString()).start(); + RP.post(new Runnable() { + @Override public void run() { + try { + listener.finished(p.waitFor() == 0); + } catch (InterruptedException x) { + listener.finished(false); + } + } + }); } catch (IOException x) { Exceptions.printStackTrace(x); + listener.finished(false); } } diff --git a/maven/nbproject/project.xml b/maven/nbproject/project.xml --- a/maven/nbproject/project.xml +++ b/maven/nbproject/project.xml @@ -240,7 +240,7 @@ 1 - 1.40 + 1.43 diff --git a/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java b/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java --- a/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java +++ b/maven/src/org/netbeans/modules/maven/ActionProviderImpl.java @@ -82,6 +82,7 @@ import org.netbeans.modules.maven.spi.actions.ActionConvertor; import org.netbeans.modules.maven.spi.actions.MavenActionsProvider; import org.netbeans.modules.maven.spi.actions.ReplaceTokenProvider; +import org.netbeans.spi.project.ActionProgress; import org.netbeans.spi.project.ActionProvider; import org.netbeans.spi.project.ProjectServiceProvider; import org.netbeans.spi.project.SingleMethod; @@ -95,11 +96,14 @@ import org.openide.awt.ActionRegistration; import org.openide.awt.DynamicMenuContent; import org.openide.awt.StatusDisplayer; +import org.openide.execution.ExecutorTask; import org.openide.loaders.DataObject; import org.openide.util.ContextAwareAction; import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.RequestProcessor; +import org.openide.util.Task; +import org.openide.util.TaskListener; import org.openide.util.actions.Presenter; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; @@ -236,7 +240,17 @@ } else { setupTaskName(action, rc, lookup); - RunUtils.run(rc); + final ActionProgress listener = ActionProgress.start(lookup); + final ExecutorTask task = RunUtils.run(rc); + if (task != null) { + task.addTaskListener(new TaskListener() { + @Override public void taskFinished(Task _) { + listener.finished(task.result() == 0); + } + }); + } else { + listener.finished(false); + } } } diff --git a/projectapi/apichanges.xml b/projectapi/apichanges.xml --- a/projectapi/apichanges.xml +++ b/projectapi/apichanges.xml @@ -108,6 +108,28 @@ + + + Added ActionProgress + + + + +

+ ActionProvider implementations should call the + new progress listener if possible. +

+
+ +

+ A new callback was added permitting the invoker of a project + action to be notified when the action completes. +

+
+ + +
+ SourceGroup.contains no longer throws IllegalArgumentException diff --git a/projectapi/manifest.mf b/projectapi/manifest.mf --- a/projectapi/manifest.mf +++ b/projectapi/manifest.mf @@ -1,7 +1,7 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.modules.projectapi/1 OpenIDE-Module-Install: org/netbeans/modules/projectapi/Installer.class -OpenIDE-Module-Specification-Version: 1.42 +OpenIDE-Module-Specification-Version: 1.43 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/projectapi/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/projectapi/layer.xml diff --git a/projectapi/nbproject/project.xml b/projectapi/nbproject/project.xml --- a/projectapi/nbproject/project.xml +++ b/projectapi/nbproject/project.xml @@ -50,6 +50,15 @@ org.netbeans.modules.projectapi + org.netbeans.api.annotations.common + + + + 1 + 1.13 + + + org.netbeans.modules.queries diff --git a/projectapi/src/org/netbeans/spi/project/ActionProgress.java b/projectapi/src/org/netbeans/spi/project/ActionProgress.java new file mode 100644 --- /dev/null +++ b/projectapi/src/org/netbeans/spi/project/ActionProgress.java @@ -0,0 +1,139 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2012 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.project; + +import org.netbeans.api.annotations.common.NonNull; +import org.openide.util.Lookup; + +/** + * Permits the invoker of an action to follow its progress. + *

An implementation may be added by a caller to the {@code context} + * of {@link ActionProvider#invokeAction}. + * If the action provider supports this interface, it should call {@link #start} + * before returning from {@code invokeAction}, and at some subsequent + * point (possibly still within {@code invokeAction} but generally later from + * a separate task thread) call {@link #finished} once on the result. + *

It is best if the provider only calls {@code start} if and when it is actually + * attempting to run an action at this time, avoiding {@code ActionProgress} entirely + * when the action is being skipped—for example, if some precondition is unsatisfied + * and a warning dialog is displayed rather than building or running anything. However + * when it would be cumbersome or impossible to determine within the dynamic scope of + * {@code invokeAction} whether or not any real action should be run, for example + * because those checks are time-consuming and should not block the event thread, + * the provider may call {@code start} and later {@code finished(false)} to signify + * that the action was not successfully run. + *

SPI example using Ant: + *

+ * {@code @}Override public void invokeAction(String command, Lookup context) {
+ *     FileObject buildXml = ...;
+ *     String[] antTargets = ...decide on targets using command...;
+ *     if (antTargets == null) { // wrong conditions, not even pretending to run this action
+ *         showWarningDialog();
+ *         return;
+ *     }
+ *     final ActionProgress listener = ActionProgress.start(context);
+ *     try {
+ *         ActionUtils.runTarget(buildXml, antTargets, null).addTaskListener(new TaskListener() {
+ *             {@code @}Override public void taskFinished(Task task) {
+ *                 listener.finished(((ExecutorTask) task).result() == 0);
+ *             }
+ *         });
+ *     } catch (IOException x) {
+ *         LOG.log(Level.FINE, "could not start program", x);
+ *         listener.finished(false);
+ *     }
+ * }
+ * 
+ * @since 1.43 + */ +public abstract class ActionProgress { + + /** + * Locates a progress listener in an action context. + * {@link #started} is called on the listener immediately. + * If none was defined by the caller, a dummy implementation is provided + * so that the {@link ActionProvider} need not do a null check. + * @param context a context as supplied to {@link ActionProvider#invokeAction} + * @return a progress listener (or dummy stub) + */ + public static @NonNull ActionProgress start(@NonNull Lookup context) { + ActionProgress ap = context.lookup(ActionProgress.class); + if (ap != null) { + ap.started(); + return ap; + } else { + return new ActionProgress() { + @Override public void started() {} + @Override public void finished(boolean success) {} + }; + } + } + + /** Constructor for subclasses. */ + protected ActionProgress() {} + + /** + * Called when the action is started. + * Serves no purpose other than confirming to the caller that this action + * provider does in fact support this interface and that it should wait + * for action completion. If this method is not called, the caller will + * not know when the action is truly finished. + * Called automatically by {@link #start}, so action providers need not pay attention. + */ + protected abstract void started(); + + /** + * Called when the action has completed. + *

The meaning of the {@code success} parameter depends on the action and may vary + * from implementation to implementation, but a caller may expect that an action + * such as {@link ActionProvider#COMMAND_BUILD} will fail if the project could not be built; + * and an action such as {@link ActionProvider#COMMAND_RUN} will fail if the program could not + * even be started (but perhaps also if it ran and terminated with an erroneous + * exit code). Some callers may ignore this parameter, + * but callers which intend to run multiple actions in succession (on the same or + * different projects) may abort the chain in case one fails. + * @param success true if the action ran normally, false if it somehow failed + */ + public abstract void finished(boolean success); + +} diff --git a/projectapi/src/org/netbeans/spi/project/ActionProvider.java b/projectapi/src/org/netbeans/spi/project/ActionProvider.java --- a/projectapi/src/org/netbeans/spi/project/ActionProvider.java +++ b/projectapi/src/org/netbeans/spi/project/ActionProvider.java @@ -175,6 +175,7 @@ * @param context any action context, e.g. for a node selection * (as in {@link ContextAwareAction}) * @throws IllegalArgumentException if the requested command is not supported + * @see ActionProgress */ void invokeAction(String command, Lookup context) throws IllegalArgumentException;