Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ActionProvider and its Lookup in NbLaunchDelegate #7059

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2542,7 +2542,7 @@ jobs:
run: tar --zstd -xf build.tar.zst

- name: java/java.lsp.server
run: .github/retry.sh ant $OPTS -f java/java.lsp.server test
run: .github/retry.sh ant $OPTS -f java/java.lsp.server clean test

- name: Create Test Summary
uses: test-summary/action@v2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public abstract class NbLaunchDelegate {
public abstract void preLaunch(Map<String, Object> launchArguments, DebugAdapterContext context);

public abstract void postLaunch(Map<String, Object> launchArguments, DebugAdapterContext context);

protected void notifyFinished(DebugAdapterContext ctx, boolean success) {
// Remove a possibly staled debugger listener
DebuggerManagerListener listener = debuggerListeners.remove(ctx);
Expand Down Expand Up @@ -167,7 +167,7 @@ public void write(String str) throws IOException {

@Override
public void flush() throws IOException {
// nop
// nop
}

@Override
Expand Down Expand Up @@ -199,10 +199,10 @@ public void progressHandleCreated(ProgressOperationEvent e) {
testProgressHandler != null ? Lookups.fixed(contextObject, ioContext, progress, testProgressHandler) : Lookups.fixed(contextObject, ioContext, progress),
Lookup.getDefault()
);

ProjectConfiguration selectConfiguration = null;
ProjectConfigurationProvider<ProjectConfiguration> pcp = null;

Object o = launchArguments.get("launchConfiguration");
if (o instanceof String) {
if (prj != null) {
Expand All @@ -218,23 +218,23 @@ public void progressHandleCreated(ProgressOperationEvent e) {
runContext.add(params);
runContext.add(ioContext);
runContext.add(progress);

Lookup lookup;
if (singleMethod != null) {
runContext.add(singleMethod);
}
if (selectConfiguration != null) {
runContext.add(selectConfiguration);
}

lookup = Lookups.fixed(runContext.toArray(new Object[runContext.size()]));
// the execution Lookup is fully populated now. If the Project supports Configurations,
// check if the action is actually enabled in the prescribed configuration. If it is not,
// check if the action is actually enabled in the prescribed configuration. If it is not,
if (pcp != null) {
final ActionProvider ap = providerAndCommand.first();
final String cmd = providerAndCommand.second();
if (!ap.isActionEnabled(cmd, lookup)) {

// attempt to locate a different configuration that enables the action:
ProjectConfiguration supportive = null;
int confIndex = runContext.indexOf(selectConfiguration);
Expand All @@ -255,10 +255,10 @@ public void progressHandleCreated(ProgressOperationEvent e) {
String msg;
String recommended = defConfig ? Bundle.ERR_LaunchDefaultConfiguration(): Bundle.ERR_LaunchSupportiveConfigName(supportive.getDisplayName());
if (debug) {
msg = supportive == null ?
msg = supportive == null ?
Bundle.ERR_UnsupportedLaunchDebug() : Bundle.ERR_UnsupportedLaunchDebugConfig(selectConfiguration.getDisplayName(), recommended);
} else {
msg = supportive == null ?
msg = supportive == null ?
Bundle.ERR_UnsupportedLaunch() : Bundle.ERR_UnsupportedLaunchConfig(selectConfiguration.getDisplayName(), recommended);
}
LanguageClient client = context.getLspSession().getLookup().lookup(LanguageClient.class);
Expand Down Expand Up @@ -487,7 +487,7 @@ private static List<String> argsToStringList(Object o) {
throw new IllegalArgumentException("Expected String or String list");
}
}

private static CompletableFuture<Pair<ActionProvider, String>> findTargetWithPossibleRebuild(Project proj, boolean preferProjActions, FileObject toRun, SingleMethod singleMethod, boolean debug, boolean testRun, NbProcessConsole ioContext) throws IllegalArgumentException {
Pair<ActionProvider, String> providerAndCommand = findTarget(proj, preferProjActions, toRun, singleMethod, debug, testRun);
if (providerAndCommand != null) {
Expand Down Expand Up @@ -550,7 +550,7 @@ public void finished(boolean success) {
ActionProvider provider = null;
String command = null;
Collection<ActionProvider> actionProviders = findActionProviders(prj);
Lookup testLookup = preferProjActions && prj != null ? Lookups.singleton(prj) : (singleMethod != null) ? Lookups.fixed(toRun, singleMethod) : Lookups.singleton(toRun);
Lookup testLookup = createTargetLookup(preferProjActions ? prj : null, singleMethod, toRun);
String[] actions;
if (!mainSource && singleMethod != null) {
actions = debug ? new String[] {SingleMethod.COMMAND_DEBUG_SINGLE_METHOD}
Expand All @@ -564,7 +564,7 @@ public void finished(boolean success) {
if (debug && !mainSource) {
// We are calling COMMAND_DEBUG_TEST_SINGLE instead of a missing COMMAND_DEBUG_TEST
// This is why we need to add the file to the lookup
testLookup = (singleMethod != null) ? Lookups.fixed(toRun, singleMethod) : Lookups.singleton(toRun);
testLookup = createTargetLookup(null, singleMethod, toRun);
}
} else {
actions = debug ? mainSource ? new String[] {ActionProvider.COMMAND_DEBUG_SINGLE}
Expand Down Expand Up @@ -625,11 +625,26 @@ public void invokeAction(String command, Lookup context) throws IllegalArgumentE
return Pair.of(provider, command);
}

private static Collection<ActionProvider> findActionProviders(Project prj) {
static Lookup createTargetLookup(Project prj, SingleMethod singleMethod, FileObject toRun) {
List<Lookup> arr = new ArrayList<>();
if (prj != null) {
arr.add(prj.getLookup());
}
if (singleMethod != null) {
Lookup methodLookup = Lookups.singleton(singleMethod);
arr.add(methodLookup);
}
if (toRun != null) {
arr.add(toRun.getLookup());
}
return new ProxyLookup(arr.toArray(new Lookup[0]));
}

static Collection<ActionProvider> findActionProviders(Project prj) {
Collection<ActionProvider> actionProviders = new ArrayList<>();
if (prj != null) {
ActionProvider ap = prj.getLookup().lookup(ActionProvider.class);
actionProviders.add(ap);
Collection<? extends ActionProvider> ap = prj.getLookup().lookupAll(ActionProvider.class);
actionProviders.addAll(ap);
}
actionProviders.addAll(Lookup.getDefault().lookupAll(ActionProvider.class));
return actionProviders;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public void showMessage(MessageParams params) {

@Override
public CompletableFuture<MessageActionItem> showMessageRequest(ShowMessageRequestParams params) {
throw new UnsupportedOperationException();
return CompletableFuture.completedFuture(new MessageActionItem(params.getActions().get(0).getTitle()));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.java.lsp.server.debugging.launch;

import java.io.IOException;
import java.util.Collection;
import org.junit.Test;
import static org.junit.Assert.*;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectManager;
import org.netbeans.spi.project.ActionProvider;
import org.netbeans.spi.project.ProjectFactory;
import org.netbeans.spi.project.ProjectState;
import org.netbeans.spi.project.SingleMethod;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.util.Lookup;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ServiceProvider;

public class NbLaunchDelegateTest {

public NbLaunchDelegateTest() {
}

@Test
public void testFileObjectsLookup() throws Exception {
FileObject fo = FileUtil.createMemoryFileSystem().getRoot().createData("test.txt");
Lookup lkp = NbLaunchDelegate.createTargetLookup(null, null, fo);
assertEquals(fo, lkp.lookup(FileObject.class));

DataObject obj = lkp.lookup(DataObject.class);
assertNotNull("DataObject also found", obj);

assertEquals("It's FileObject's data object", obj, DataObject.find(fo));
assertNull("No single method", lkp.lookup(SingleMethod.class));
}

@Test
public void testFileObjectsLookupWithSingleMethod() throws Exception {
FileObject fo = FileUtil.createMemoryFileSystem().getRoot().createData("test-with-method.txt");
SingleMethod m = new SingleMethod(fo, "main");
Lookup lkp = NbLaunchDelegate.createTargetLookup(null, m, fo);
assertEquals(fo, lkp.lookup(FileObject.class));

DataObject obj = lkp.lookup(DataObject.class);
assertNotNull("DataObject also found", obj);

assertEquals("It's FileObject's data object", obj, DataObject.find(fo));

assertEquals("Found single method", m, lkp.lookup(SingleMethod.class));
}

@Test
public void testFindsMavenProject() throws Exception {
FileObject dir = FileUtil.createMemoryFileSystem().getRoot().createFolder("testprj");
FileObject xml = dir.createData("build.xml");
Project prj = ProjectManager.getDefault().findProject(dir);
assertNotNull("Project dir recognized", prj);

SingleMethod m = new SingleMethod(xml, "main");
Lookup lkp = NbLaunchDelegate.createTargetLookup(prj, null, null);
assertNull("No file object", lkp.lookup(FileObject.class));
DataObject obj = lkp.lookup(DataObject.class);
assertNull("No DataObject ", obj);
assertNull("No single method", lkp.lookup(SingleMethod.class));
assertEquals(prj, lkp.lookup(Project.class));
}

@Test
public void testFindsWithFileObjectAndDataObject() throws Exception {
FileObject dir = FileUtil.createMemoryFileSystem().getRoot().createFolder("testprj");
FileObject xml = dir.createData("build.xml");
Project prj = ProjectManager.getDefault().findProject(dir);
assertNotNull("Project dir recognized", prj);

SingleMethod m = new SingleMethod(xml, "main");
Lookup lkp = NbLaunchDelegate.createTargetLookup(prj, m, xml);
assertEquals("File object is available", xml, lkp.lookup(FileObject.class));
DataObject obj = lkp.lookup(DataObject.class);
assertNotNull("DataObject is available", obj);
assertEquals("DataObject's FileObject is correct", xml, obj.getPrimaryFile());
assertEquals("Single method is also present", m, lkp.lookup(SingleMethod.class));
assertEquals(prj, lkp.lookup(Project.class));
}

@Test
public void testAvoidNPEWithoutActionsProviderInLookup() throws Exception {
MockProjectFactory.MockProject prj = new MockProjectFactory.MockProject(FileUtil.getConfigRoot());
Collection<ActionProvider> all = NbLaunchDelegate.findActionProviders(prj);
assertFalse("There shall be no null in " + all, all.contains(null));
}

@ServiceProvider(service = ProjectFactory.class)
public static final class MockProjectFactory implements ProjectFactory {

@Override
public boolean isProject(FileObject projectDirectory) {
return projectDirectory.getNameExt().equals("testprj");
}

@Override
public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException {
if (isProject(projectDirectory)) {
return new MockProject(projectDirectory);
} else {
return null;
}
}

@Override
public void saveProject(Project project) throws IOException, ClassCastException {
}

private static final class MockProject implements Project {
private final FileObject dir;

MockProject(FileObject dir) {
this.dir = dir;
}

@Override
public FileObject getProjectDirectory() {
return dir;
}

@Override
public Lookup getLookup() {
return Lookups.fixed(this);
}

}
}
}
Loading
Loading