From b6dc0d4cd990fb3e5b4bad605eaaadc0aab6f294 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Mon, 16 Oct 2023 17:42:04 +0200 Subject: [PATCH 01/11] Prefixing all code names of commands with 'nbls'. --- .../infrastructure/JavaErrorProvider.java | 4 +- .../commands/ProjectAuditCommand.java | 2 +- .../commands/ProjectMetadataCommand.java | 2 +- .../modules/java/lsp/server/Utils.java | 40 ++++++ .../java/lsp/server/db/DBAddConnection.java | 4 +- .../java/lsp/server/db/DBCommandProvider.java | 4 +- .../lsp/server/db/DBConnectionProvider.java | 6 +- .../attach/AttachConfigurationCompletion.java | 21 +++- .../attach/AttachConfigurations.java | 13 +- .../attach/ConfigurationAttributes.java | 6 +- .../attach/NbAttachRequestHandler.java | 5 +- .../server/explorer/NodeActionsProvider.java | 2 +- .../explorer/NodePropertiesProvider.java | 4 +- .../java/lsp/server/htmlui/WebView.java | 4 +- .../server/protocol/CodeActionsProvider.java | 6 +- .../server/protocol/ConstructorGenerator.java | 4 +- .../protocol/DelegateMethodGenerator.java | 4 +- .../protocol/EqualsHashCodeGenerator.java | 8 +- .../protocol/GetterSetterGenerator.java | 8 +- .../ImplementAllAbstractMethodsAction.java | 4 +- .../ImplementOverrideMethodGenerator.java | 6 +- .../LaunchConfigurationCompletion.java | 4 + .../lsp/server/protocol/LoggerGenerator.java | 4 +- .../protocol/NbCodeClientCapabilities.java | 40 ++++++ .../protocol/OrganizeImportsCodeAction.java | 4 +- .../ProjectConfigurationCompletion.java | 11 +- .../java/lsp/server/protocol/QuickOpen.java | 4 +- .../java/lsp/server/protocol/Server.java | 75 ++++++------ .../lsp/server/protocol/SurroundWithHint.java | 8 +- .../server/protocol/TestClassGenerator.java | 6 +- .../protocol/TextDocumentServiceImpl.java | 22 ++-- .../server/protocol/ToStringGenerator.java | 4 +- .../server/protocol/WorkspaceServiceImpl.java | 47 +++++--- .../ChangeMethodParametersRefactoring.java | 6 +- ...tractSuperclassOrInterfaceRefactoring.java | 10 +- .../server/refactoring/MoveRefactoring.java | 8 +- .../server/refactoring/PullUpRefactoring.java | 6 +- .../refactoring/PushDownRefactoring.java | 6 +- .../EnablePreviewSingleSourceFile.java | 4 +- .../lsp/server/explorer/ProjectViewTest.java | 2 +- .../java/lsp/server/protocol/ServerTest.java | 16 +-- java/java.lsp.server/vscode/package.json | 114 +++++++++--------- .../vscode/src/dbConfigurationProvider.ts | 4 +- java/java.lsp.server/vscode/src/extension.ts | 87 ++++++------- .../vscode/src/launchConfigurations.ts | 7 +- .../vscode/src/test/suite/extension.test.ts | 22 ++-- .../vscode/src/test/suite/testutils.ts | 6 +- .../java.lsp.server/vscode/src/testAdapter.ts | 9 +- .../openjdk/jtreg/CodeLensProviderImpl.java | 4 +- 49 files changed, 414 insertions(+), 283 deletions(-) diff --git a/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java b/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java index 9e5c5e69c40c..a756a2e9bd72 100644 --- a/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java +++ b/java/java.hints/src/org/netbeans/modules/java/hints/infrastructure/JavaErrorProvider.java @@ -194,14 +194,14 @@ private static List convertFixes(ErrorDescription err, Consumer params = rf.getNewSourceLevel() != null ? Arrays.asList(rf.getNewSourceLevel()) : Collections.emptyList(); - CodeAction action = new CodeAction(f.getText(), new Command(f.getText(), "java.project.enable.preview", params)); + CodeAction action = new CodeAction(f.getText(), new Command(f.getText(), "nbls.java.project.enable.preview", params)); result.add(action); } if (f instanceof ImportClass.FixImport) { diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectAuditCommand.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectAuditCommand.java index 0c9da35497d6..05e8f12cfc1b 100644 --- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectAuditCommand.java +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectAuditCommand.java @@ -87,7 +87,7 @@ public class ProjectAuditCommand extends CodeActionsProvider { )); @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectMetadataCommand.java b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectMetadataCommand.java index f83c433bc8e4..30e0142b2db1 100644 --- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectMetadataCommand.java +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/commands/ProjectMetadataCommand.java @@ -74,7 +74,7 @@ public ProjectMetadataCommand() { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java index d913aab26e31..74321bec9224 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/Utils.java @@ -26,11 +26,13 @@ import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URI; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; @@ -50,6 +52,7 @@ import org.netbeans.api.java.source.CompilationInfo; import org.netbeans.api.lsp.StructureElement; import org.netbeans.modules.editor.java.Utilities; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.netbeans.modules.parsing.spi.indexing.support.QuerySupport; import org.netbeans.spi.jumpto.type.SearchType; import org.openide.cookies.EditorCookie; @@ -64,6 +67,8 @@ */ public class Utils { + public static final String DEFAULT_COMMAND_PREFIX = "nbls"; + public static SymbolKind structureElementKind2SymbolKind (StructureElement.Kind kind) { switch (kind) { case Array : return SymbolKind.Array; @@ -488,4 +493,39 @@ public static String html2plain(String s, boolean collapseWhitespaces) { public static String html2plain(String s) { return html2plain(s, false); } + + public static String encodeCommand(String cmd, NbCodeClientCapabilities capa) { + String prefix = capa != null ? capa.getCommandPrefix() + : DEFAULT_COMMAND_PREFIX; + + if (cmd.startsWith(DEFAULT_COMMAND_PREFIX) && + !DEFAULT_COMMAND_PREFIX.equals(prefix)) { + return prefix + cmd.substring(DEFAULT_COMMAND_PREFIX.length()); + } else { + return cmd; + } + } + + public static String decodeCommand(String cmd, NbCodeClientCapabilities capa) { + String prefix = capa != null ? capa.getCommandPrefix() + : DEFAULT_COMMAND_PREFIX; + + if (cmd.startsWith(prefix) && + !DEFAULT_COMMAND_PREFIX.equals(prefix)) { + return DEFAULT_COMMAND_PREFIX + cmd.substring(prefix.length()); + } else { + return cmd; + } + } + + public static void ensureCommandsPrefixed(Collection commands) { + Set wrongCommands = commands.stream() + .filter(cmd -> !cmd.startsWith(DEFAULT_COMMAND_PREFIX)) + .filter(cmd -> !cmd.startsWith("test.")) + .collect(Collectors.toSet()); + + if (!wrongCommands.isEmpty()) { + throw new IllegalStateException("Some commands are not properly prefixed: " + wrongCommands); + } + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBAddConnection.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBAddConnection.java index 5b00a58bec9c..557edb649cc2 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBAddConnection.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBAddConnection.java @@ -75,7 +75,7 @@ }) @ServiceProvider(service = CodeActionsProvider.class) public class DBAddConnection extends CodeActionsProvider { - public static final String DB_ADD_CONNECTION = "db.add.connection"; // NOI18N + public static final String DB_ADD_CONNECTION = "nbls.db.add.connection"; // NOI18N public static final String USER_ID = "userId"; // NOI18N public static final String PASSWORD = "password"; // NOI18N public static final String DRIVER = "driver"; // NOI18N @@ -306,7 +306,7 @@ public Set getCommands() { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBCommandProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBCommandProvider.java index 79850e77fbca..1925d3837655 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBCommandProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBCommandProvider.java @@ -41,10 +41,10 @@ */ @ServiceProvider(service = CodeActionsProvider.class) public class DBCommandProvider extends CodeActionsProvider { - private static final String COMMAND_GET_PREFERRED_CONNECTION = "java.db.preferred.connection"; + private static final String COMMAND_GET_PREFERRED_CONNECTION = "nbls.db.preferred.connection"; @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBConnectionProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBConnectionProvider.java index 8c01aedfb36a..239890a9e8da 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBConnectionProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/db/DBConnectionProvider.java @@ -62,8 +62,8 @@ */ @ServiceProvider(service = CodeActionsProvider.class) public class DBConnectionProvider extends CodeActionsProvider{ - private static final Logger LOG = Logger.getLogger(DBConnectionProvider.class.getName()); - private static final String GET_DB_CONNECTION = "java.db.connection"; //NOI18N + private static final Logger LOG = Logger.getLogger(DBConnectionProvider.class.getName()); + private static final String GET_DB_CONNECTION = "nbls.db.connection"; //NOI18N private static final boolean POSIX = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); // NOI18N private static final EnumSet readWritePosix = EnumSet.of(OWNER_READ, OWNER_WRITE); @@ -81,7 +81,7 @@ public DBConnectionProvider() { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurationCompletion.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurationCompletion.java index 5ff3e14209bc..dcdfca095d7e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurationCompletion.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurationCompletion.java @@ -35,6 +35,7 @@ import org.netbeans.api.project.Project; import org.netbeans.modules.java.lsp.server.Utils; import org.netbeans.modules.java.lsp.server.protocol.LaunchConfigurationCompletion; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.openide.util.Exceptions; import org.openide.util.lookup.ServiceProvider; @@ -43,20 +44,25 @@ * * @author Martin Entlicher */ -@ServiceProvider(service = LaunchConfigurationCompletion.class, position = 200) public class AttachConfigurationCompletion implements LaunchConfigurationCompletion { + private final NbCodeClientCapabilities capa; + + public AttachConfigurationCompletion(NbCodeClientCapabilities capa) { + this.capa = capa; + } + @Override public CompletableFuture> configurations(Supplier> projectSupplier) { return CompletableFuture.supplyAsync(() -> { - return createCompletion(AttachConfigurations.get()); + return createCompletion(AttachConfigurations.get(capa)); }, AttachConfigurations.RP); } @Override public CompletableFuture> attributes(Supplier> projectSupplier, Map currentAttributes) { return CompletableFuture.supplyAsync(() -> { - return createAttributesCompletion(AttachConfigurations.get(), currentAttributes); + return createAttributesCompletion(AttachConfigurations.get(capa), currentAttributes); }, AttachConfigurations.RP); } @@ -140,4 +146,13 @@ private static List createAttributesCompletion(AttachConfigurati } } + @ServiceProvider(service = Factory.class, position = 200) + public static final class FactoryImpl implements Factory { + + @Override + public LaunchConfigurationCompletion createLaunchConfigurationCompletion(NbCodeClientCapabilities capa) { + return new AttachConfigurationCompletion(capa); + } + + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurations.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurations.java index 7989a0598b4b..87ec97a64b9d 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurations.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/AttachConfigurations.java @@ -44,6 +44,7 @@ import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; import org.netbeans.modules.java.lsp.server.input.QuickPickItem; import org.netbeans.modules.java.lsp.server.input.ShowQuickPickParams; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.openide.util.NbBundle.Messages; import org.openide.util.RequestProcessor; @@ -61,26 +62,26 @@ public final class AttachConfigurations { private final List configurations; - private AttachConfigurations(List attachingConnectors) { + private AttachConfigurations(NbCodeClientCapabilities capa, List attachingConnectors) { List configs = new ArrayList<>(5); for (Connector ac : attachingConnectors) { - configs.add(new ConfigurationAttributes(ac)); + configs.add(new ConfigurationAttributes(capa, ac)); } this.configurations = Collections.unmodifiableList(configs); } - public static AttachConfigurations get() { + public static AttachConfigurations get(NbCodeClientCapabilities capa) { List attachingConnectors = Bootstrap.virtualMachineManager().attachingConnectors(); List listeningConnectors = Bootstrap.virtualMachineManager().listeningConnectors(); List connectors = new ArrayList<>(attachingConnectors.size() + listeningConnectors.size()); connectors.addAll(attachingConnectors); connectors.addAll(listeningConnectors); - return new AttachConfigurations(connectors); + return new AttachConfigurations(capa, connectors); } - public static CompletableFuture findConnectors() { + public static CompletableFuture findConnectors(NbCodeClientCapabilities capa) { return CompletableFuture.supplyAsync(() -> { - return get().listAttachingConnectors(); + return get(capa).listAttachingConnectors(); }, RP); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/ConfigurationAttributes.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/ConfigurationAttributes.java index 58ba4f9d216f..50f0dbbd807b 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/ConfigurationAttributes.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/ConfigurationAttributes.java @@ -25,6 +25,8 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; +import org.netbeans.modules.java.lsp.server.Utils; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.netbeans.modules.java.lsp.server.protocol.Server; import org.openide.util.NbBundle; @@ -63,7 +65,7 @@ final class ConfigurationAttributes { "DESC_HostName=Name or IP address of the host machine to connect to", "DESC_Port=Port number to connect to", "DESC_ShMem=Shared memory transport address at which the target VM is listening"}) - ConfigurationAttributes(Connector ac) { + ConfigurationAttributes(NbCodeClientCapabilities capa, Connector ac) { this.ac = ac; String connectorName = ac.name(); this.id = connectorName; @@ -72,7 +74,7 @@ final class ConfigurationAttributes { switch (connectorName) { case CONNECTOR_PROCESS: this.name = Bundle.LBL_AttachToProcess(); - attributes.put(PROCESS_ARG_PID, new ConfigurationAttribute("${command:" + Server.JAVA_FIND_DEBUG_PROCESS_TO_ATTACH + "}", "", true)); // NOI18N + attributes.put(PROCESS_ARG_PID, new ConfigurationAttribute("${command:" + Utils.encodeCommand(Server.JAVA_FIND_DEBUG_PROCESS_TO_ATTACH, capa) + "}", "", true)); // NOI18N break; case CONNECTOR_SOCKET: this.name = Bundle.LBL_AttachToPort(); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/NbAttachRequestHandler.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/NbAttachRequestHandler.java index 9563381f2669..1b483fed54f5 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/NbAttachRequestHandler.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/debugging/attach/NbAttachRequestHandler.java @@ -51,6 +51,7 @@ import org.netbeans.modules.java.lsp.server.debugging.launch.NbDebugSession; import org.netbeans.modules.java.lsp.server.debugging.ni.NILocationVisualizer; import org.netbeans.modules.java.lsp.server.debugging.utils.ErrorUtilities; +import org.netbeans.modules.java.lsp.server.protocol.NbCodeClientCapabilities; import org.netbeans.modules.java.lsp.server.protocol.NbCodeLanguageClient; import org.netbeans.modules.java.nativeimage.debugger.api.NIDebugRunner; import org.netbeans.modules.nativeimage.api.debug.NIDebugger; @@ -163,7 +164,9 @@ private void attachNativeDebug(File nativeImageFile, long processId, String miDe @Messages({"# {0} - connector name", "MSG_InvalidConnector=Invalid connector name: {0}"}) private CompletableFuture attachToJVM(Map attachArguments, DebugAdapterContext context) { CompletableFuture resultFuture = new CompletableFuture<>(); - ConfigurationAttributes configurationAttributes = AttachConfigurations.get().findConfiguration(attachArguments); + NbCodeLanguageClient client = context.getLspSession().getLookup().lookup(NbCodeLanguageClient.class); + NbCodeClientCapabilities clientCapa = client != null ? client.getNbCodeCapabilities() : null; + ConfigurationAttributes configurationAttributes = AttachConfigurations.get(clientCapa).findConfiguration(attachArguments); if (configurationAttributes != null) { Connector connector = configurationAttributes.getConnector(); RP.post(() -> attachTo(connector, attachArguments, context, resultFuture)); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodeActionsProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodeActionsProvider.java index a78663856191..8c41ef1211d3 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodeActionsProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodeActionsProvider.java @@ -90,7 +90,7 @@ public static NodeActionsProvider forFile(FileObject f) { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodePropertiesProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodePropertiesProvider.java index 2d74a57288b8..f20e40acc987 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodePropertiesProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/explorer/NodePropertiesProvider.java @@ -52,7 +52,7 @@ public class NodePropertiesProvider extends CodeActionsProvider { private static final Logger LOG = Logger.getLogger(NodePropertiesProvider.class.getName()); - private static final String COMMAND_PREFIX = "java."; + private static final String COMMAND_PREFIX = "nbls."; private static final String COMMAND_GET_NODE_PROPERTIES = COMMAND_PREFIX + "node.properties.get"; // NOI18N private static final String COMMAND_SET_NODE_PROPERTIES = COMMAND_PREFIX + "node.properties.set"; // NOI18N @@ -76,7 +76,7 @@ public class NodePropertiesProvider extends CodeActionsProvider { private final Gson gson = new Gson(); @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/WebView.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/WebView.java index 2e7918b2c601..7b91b8974527 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/WebView.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/htmlui/WebView.java @@ -369,7 +369,7 @@ private static Level findLevel(int priority) { public static final class Server extends CodeActionsProvider { private static final Map SESSIONS = new HashMap<>(); - private static final String PROCESS_COMMAND = "nb.htmlui.process.command"; // NOI18N + private static final String PROCESS_COMMAND = "nbls.htmlui.process.command"; // NOI18N private static final String ID = "id"; // NOI18N private final Gson gson = new Gson(); @@ -394,7 +394,7 @@ public CompletableFuture processCommand(NbCodeLanguageClient client, Str } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } } // end of Server diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java index c73402c00163..f9a1378e348f 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/CodeActionsProvider.java @@ -54,7 +54,7 @@ public abstract class CodeActionsProvider { public static final String DATA = "data"; protected static final String ERROR = ""; //NOI18N - public abstract List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception; + public abstract List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception; public CompletableFuture resolve(NbCodeLanguageClient client, CodeAction codeAction, Object data) { return CompletableFuture.completedFuture(codeAction); @@ -68,11 +68,11 @@ public CompletableFuture processCommand(NbCodeLanguageClient client, Str return CompletableFuture.completedFuture(false); } - protected CodeAction createCodeAction(String name, String kind, Object data, String command, Object... commandArgs) { + protected CodeAction createCodeAction(NbCodeLanguageClient client, String name, String kind, Object data, String command, Object... commandArgs) { CodeAction action = new CodeAction(name); action.setKind(kind); if (command != null) { - action.setCommand(new Command(name, command, Arrays.asList(commandArgs))); + action.setCommand(new Command(name, Utils.encodeCommand(command, client.getNbCodeCapabilities()), Arrays.asList(commandArgs))); } if (data != null) { Map map = new HashMap<>(); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java index 6d932ec40ad9..1d16573dae6a 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ConstructorGenerator.java @@ -91,7 +91,7 @@ public ConstructorGenerator() { @NbBundle.Messages({ "DN_GenerateConstructor=Generate Constructor...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { CompilationController info = resultIterator.getParserResult() != null ? CompilationController.get(resultIterator.getParserResult()) : null; if (info == null) { return Collections.emptyList(); @@ -187,7 +187,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction data.put(OFFSET, startOffset); data.put(CONSTRUCTORS, constructors); data.put(FIELDS, fields); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateConstructor(), isSource ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data, "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateConstructor(), isSource ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data, "workbench.action.focusActiveEditorGroup")); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java index 52dd026f751a..6b689ebdeb45 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/DelegateMethodGenerator.java @@ -85,7 +85,7 @@ public final class DelegateMethodGenerator extends CodeActionsProvider { @NbBundle.Messages({ "DN_GenerateDelegateMethod=Generate Delegate Method...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source)) { return Collections.emptyList(); @@ -135,7 +135,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction data.put(OFFSET, offset); data.put(TYPE, typeItem); data.put(FIELDS, fields); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateDelegateMethod(), CODE_GENERATOR_KIND, data, "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateDelegateMethod(), CODE_GENERATOR_KIND, data, "workbench.action.focusActiveEditorGroup")); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java index 53462077ec0e..117c174a7d7e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/EqualsHashCodeGenerator.java @@ -75,7 +75,7 @@ public final class EqualsHashCodeGenerator extends CodeActionsProvider { "DN_GenerateHashCode=Generate hashCode()...", "DN_GenerateEqualsHashCode=Generate equals() and hashCode()...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source)) { return Collections.emptyList(); @@ -113,11 +113,11 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction String uri = Utils.toUri(info.getFileObject()); if (equalsHashCode[0] == null) { if (equalsHashCode[1] == null) { - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEqualsHashCode(), CODE_GENERATOR_KIND, data(0, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateEqualsHashCode(), CODE_GENERATOR_KIND, data(0, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); } - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateEquals(), CODE_GENERATOR_KIND, data(EQUALS_ONLY, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateEquals(), CODE_GENERATOR_KIND, data(EQUALS_ONLY, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); } - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateHashCode(), CODE_GENERATOR_KIND, data(HASH_CODE_ONLY, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateHashCode(), CODE_GENERATOR_KIND, data(HASH_CODE_ONLY, uri, offset, fields), "workbench.action.focusActiveEditorGroup")); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java index 87fce47ac137..84b23ba44447 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/GetterSetterGenerator.java @@ -86,7 +86,7 @@ public final class GetterSetterGenerator extends CodeActionsProvider { "DN_GenerateSetterFor=Generate Setter for \"{0}\"", "DN_GenerateGetterSetterFor=Generate Getter and Setter for \"{0}\"", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { CompilationController info = resultIterator.getParserResult() != null ? CompilationController.get(resultIterator.getParserResult()) : null; if (info == null) { return Collections.emptyList(); @@ -102,7 +102,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction List result = new ArrayList<>(); if (missingGetters) { String name = pair.first().size() == 1 ? Bundle.DN_GenerateGetterFor(pair.first().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateGetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.GETTERS_ONLY, uri, offset, all, pair.first().stream().map(variableElement -> { + result.add(createCodeAction(client, name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.GETTERS_ONLY, uri, offset, all, pair.first().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; @@ -110,7 +110,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction } if (missingSetters) { String name = pair.second().size() == 1 ? Bundle.DN_GenerateSetterFor(pair.second().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateSetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.SETTERS_ONLY, uri, offset, all, pair.second().stream().map(variableElement -> { + result.add(createCodeAction(client, name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(GeneratorUtils.SETTERS_ONLY, uri, offset, all, pair.second().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; @@ -119,7 +119,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction if (missingGetters && missingSetters) { pair.first().retainAll(pair.second()); String name = pair.first().size() == 1 ? Bundle.DN_GenerateGetterSetterFor(pair.first().iterator().next().getSimpleName().toString()) : Bundle.DN_GenerateGettersSetters(); - result.add(createCodeAction(name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(0, uri, offset, all, pair.first().stream().map(variableElement -> { + result.add(createCodeAction(client, name, all ? CODE_GENERATOR_KIND : CodeActionKind.QuickFix, data(0, uri, offset, all, pair.first().stream().map(variableElement -> { QuickPickItem item = new QuickPickItem(createLabel(info, variableElement)); item.setUserData(new ElementData(variableElement)); return item; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementAllAbstractMethodsAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementAllAbstractMethodsAction.java index e611c23d81ff..cfb5175723e4 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementAllAbstractMethodsAction.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementAllAbstractMethodsAction.java @@ -47,11 +47,11 @@ @ServiceProvider(service = CodeActionsProvider.class, position = 200) public final class ImplementAllAbstractMethodsAction extends CodeActionsProvider { - private static final String IMPLEMENT_ALL_ABSTRACT_METHODS = "java.implement.all.abstract.methods"; //NOI18N + private static final String IMPLEMENT_ALL_ABSTRACT_METHODS = "nbls.java.implement.all.abstract.methods"; //NOI18N private final Gson gson = new Gson(); @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java index 119a40cb06ed..d3d2c8d43a6b 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ImplementOverrideMethodGenerator.java @@ -75,7 +75,7 @@ public final class ImplementOverrideMethodGenerator extends CodeActionsProvider "DN_GenerateOverrideMethod=Generate Override Method...", "DN_From=(from {0})", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source)) { return Collections.emptyList(); @@ -107,7 +107,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction implementMethods.add(new QuickPickItem(createLabel(info, method), enclosingTypeName, null, mustImplement, new ElementData(method))); } if (!implementMethods.isEmpty()) { - result.add(createCodeAction(Bundle.DN_GenerateImplementMethod(), CODE_GENERATOR_KIND, data(uri, offset, true, implementMethods), "workbench.action.focusActiveEditorGroup")); + result.add(createCodeAction(client, Bundle.DN_GenerateImplementMethod(), CODE_GENERATOR_KIND, data(uri, offset, true, implementMethods), "workbench.action.focusActiveEditorGroup")); } } if (typeElement.getKind().isClass() || typeElement.getKind().isInterface()) { @@ -123,7 +123,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction overrideMethods.add(item); } if (!overrideMethods.isEmpty()) { - result.add(createCodeAction(Bundle.DN_GenerateOverrideMethod(), CODE_GENERATOR_KIND, data (uri, offset, false, overrideMethods), "workbench.action.focusActiveEditorGroup")); + result.add(createCodeAction(client, Bundle.DN_GenerateOverrideMethod(), CODE_GENERATOR_KIND, data (uri, offset, false, overrideMethods), "workbench.action.focusActiveEditorGroup")); } } return result; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LaunchConfigurationCompletion.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LaunchConfigurationCompletion.java index 40ec50f9b495..ac5150b93ace 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LaunchConfigurationCompletion.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LaunchConfigurationCompletion.java @@ -65,4 +65,8 @@ public interface LaunchConfigurationCompletion { */ @NonNull CompletableFuture> attributeValues(Supplier> projectSupplier, Map attributes, String attributeName); + + public interface Factory { + public LaunchConfigurationCompletion createLaunchConfigurationCompletion(NbCodeClientCapabilities capa); + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java index d39a5d997f6b..fbea183809ae 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/LoggerGenerator.java @@ -75,7 +75,7 @@ public LoggerGenerator() { @NbBundle.Messages({ "DN_GenerateLogger=Generate Logger...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source)) { return Collections.emptyList(); @@ -106,7 +106,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction Map data = new HashMap<>(); data.put(URI, uri); data.put(OFFSET, offset); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateLogger(), CODE_GENERATOR_KIND, data, "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateLogger(), CODE_GENERATOR_KIND, data, "workbench.action.focusActiveEditorGroup")); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java index 1e869eec3847..9134992f5f38 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/NbCodeClientCapabilities.java @@ -22,6 +22,7 @@ import com.google.gson.JsonElement; import org.eclipse.lsp4j.ClientCapabilities; import org.eclipse.lsp4j.InitializeParams; +import org.netbeans.modules.java.lsp.server.Utils; /** * Encapsulates all nbcode-specific client capabilities. Need to be passed in @@ -75,6 +76,21 @@ public final class NbCodeClientCapabilities { */ private Boolean wantsGroovySupport = Boolean.TRUE; + /** + * Common prefix for all commands. + */ + private String commandPrefix = Utils.DEFAULT_COMMAND_PREFIX; + + /** + * Common prefix for configuration. + */ + private String configurationPrefix = "netbeans."; + + /** + * Secondary prefix for configuration. + */ + private String altConfigurationPrefix = "java+."; + public ClientCapabilities getClientCapabilities() { return clientCaps; } @@ -139,6 +155,30 @@ public boolean wantsGroovySupport() { return wantsGroovySupport.booleanValue(); } + public String getCommandPrefix() { + return commandPrefix; + } + + public void setCommandPrefix(String commandPrefix) { + this.commandPrefix = commandPrefix; + } + + public String getConfigurationPrefix() { + return configurationPrefix; + } + + public void setConfigurationPrefix(String configurationPrefix) { + this.configurationPrefix = configurationPrefix; + } + + public String getAltConfigurationPrefix() { + return altConfigurationPrefix; + } + + public void setAltConfigurationPrefix(String altConfigurationPrefix) { + this.altConfigurationPrefix = altConfigurationPrefix; + } + private NbCodeClientCapabilities withCapabilities(ClientCapabilities caps) { if (caps == null) { caps = new ClientCapabilities(); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java index d912c42c95d9..42b3676c5658 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/OrganizeImportsCodeAction.java @@ -48,7 +48,7 @@ public final class OrganizeImportsCodeAction extends CodeActionsProvider { @NbBundle.Messages({ "DN_OrganizeImports=Organize Imports", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source) && !only.contains(CodeActionKind.SourceOrganizeImports)) { return Collections.emptyList(); @@ -58,7 +58,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction return Collections.emptyList(); } String uri = Utils.toUri(info.getFileObject()); - return Collections.singletonList(createCodeAction(Bundle.DN_OrganizeImports(), CodeActionKind.SourceOrganizeImports, uri, null)); + return Collections.singletonList(createCodeAction(client, Bundle.DN_OrganizeImports(), CodeActionKind.SourceOrganizeImports, uri, null)); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ProjectConfigurationCompletion.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ProjectConfigurationCompletion.java index 4a3e4098ab4b..91bf8e30dbe0 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ProjectConfigurationCompletion.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ProjectConfigurationCompletion.java @@ -44,7 +44,6 @@ * * @author Martin Entlicher */ -@ServiceProvider(service = LaunchConfigurationCompletion.class, position = 100) public class ProjectConfigurationCompletion implements LaunchConfigurationCompletion { private static final String CONFIG_TYPE = "java+"; // NOI18N @@ -136,4 +135,14 @@ private static Collection getConfigurations(Project p) { } return provider.getConfigurations(); } + + @ServiceProvider(service = Factory.class, position = 100) + public static final class FactoryImpl implements Factory { + + @Override + public LaunchConfigurationCompletion createLaunchConfigurationCompletion(NbCodeClientCapabilities capa) { + return new ProjectConfigurationCompletion(); + } + + } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/QuickOpen.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/QuickOpen.java index 69f7870af823..2a1177731e3e 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/QuickOpen.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/QuickOpen.java @@ -61,7 +61,7 @@ @ServiceProvider(service = CodeActionsProvider.class) public class QuickOpen extends CodeActionsProvider { - public static final String QUICK_OPEN = "java.quick.open"; // NOI18N + public static final String QUICK_OPEN = "nbls.quick.open"; // NOI18N public static final String DEFAULT_PKG = ""; // NOI18N private final Gson gson = new Gson(); @@ -131,7 +131,7 @@ public CompletableFuture processCommand(NbCodeLanguageClient client, Str } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java index f846fdb95265..d0f582bc6eac 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/Server.java @@ -49,6 +49,7 @@ import java.util.LinkedHashSet; import java.util.WeakHashMap; import java.util.concurrent.CompletionException; +import java.util.stream.Collectors; import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.lsp4j.CallHierarchyRegistrationOptions; import org.eclipse.lsp4j.CodeActionKind; @@ -358,8 +359,8 @@ public Project next() { public static class LanguageServerImpl implements LanguageServer, LanguageClientAware, LspServerState, NbLanguageServer { - private static final String NETBEANS_FORMAT = "netbeans.format"; - private static final String NETBEANS_JAVA_IMPORTS = "netbeans.java.imports"; + private static final String NETBEANS_FORMAT = "format"; + private static final String NETBEANS_JAVA_IMPORTS = "java.imports"; // change to a greater throughput if the initialization waits on more processes than just (serialized) project open. private static final RequestProcessor SERVER_INIT_RP = new RequestProcessor(LanguageServerImpl.class.getName()); @@ -772,7 +773,7 @@ private void showStatusBarMessage(final MessageType type, final String msg, int } } - private InitializeResult constructInitResponse(InitializeParams init, JavaSource src) { + private InitializeResult constructInitResponse(InitializeParams init, JavaSource src, NbCodeClientCapabilities capa) { ServerCapabilities capabilities = new ServerCapabilities(); if (src != null) { TextDocumentSyncOptions textDocumentSyncOptions = new TextDocumentSyncOptions(); @@ -804,33 +805,35 @@ private InitializeResult constructInitResponse(InitializeParams init, JavaSource CallHierarchyRegistrationOptions chOpts = new CallHierarchyRegistrationOptions(); chOpts.setWorkDoneProgress(true); capabilities.setCallHierarchyProvider(chOpts); - Set commands = new LinkedHashSet<>(Arrays.asList(GRAALVM_PAUSE_SCRIPT, + Set commands = new LinkedHashSet<>(Arrays.asList(NBLS_GRAALVM_PAUSE_SCRIPT, NBLS_BUILD_WORKSPACE, NBLS_CLEAN_WORKSPACE, NBLS_GET_ARCHIVE_FILE_CONTENT, - JAVA_RUN_PROJECT_ACTION, + NBLS_RUN_PROJECT_ACTION, JAVA_FIND_DEBUG_ATTACH_CONFIGURATIONS, JAVA_FIND_DEBUG_PROCESS_TO_ATTACH, - JAVA_FIND_PROJECT_CONFIGURATIONS, + NBLS_FIND_PROJECT_CONFIGURATIONS, JAVA_GET_PROJECT_CLASSPATH, JAVA_GET_PROJECT_PACKAGES, JAVA_GET_PROJECT_SOURCE_ROOTS, - JAVA_LOAD_WORKSPACE_TESTS, - JAVA_RESOLVE_STACKTRACE_LOCATION, - JAVA_NEW_FROM_TEMPLATE, - JAVA_NEW_PROJECT, - JAVA_PROJECT_CONFIGURATION_COMPLETION, - JAVA_PROJECT_RESOLVE_PROJECT_PROBLEMS, + NBLS_LOAD_WORKSPACE_TESTS, + NBLS_RESOLVE_STACKTRACE_LOCATION, + NBLS_NEW_FROM_TEMPLATE, + NBLS_NEW_PROJECT, + NBLS_PROJECT_CONFIGURATION_COMPLETION, + NBLS_PROJECT_RESOLVE_PROJECT_PROBLEMS, JAVA_SUPER_IMPLEMENTATION, - JAVA_CLEAR_PROJECT_CACHES, + NBLS_CLEAR_PROJECT_CACHES, NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH, - JAVA_PROJECT_INFO, + NBLS_PROJECT_INFO, JAVA_ENABLE_PREVIEW, NBLS_DOCUMENT_SYMBOLS )); for (CodeActionsProvider codeActionsProvider : Lookup.getDefault().lookupAll(CodeActionsProvider.class)) { commands.addAll(codeActionsProvider.getCommands()); } + Utils.ensureCommandsPrefixed(commands); + commands = commands.stream().map(cmd -> Utils.encodeCommand(cmd, capa)).collect(Collectors.toSet()); capabilities.setExecuteCommandProvider(new ExecuteCommandOptions(new ArrayList<>(commands))); WorkspaceSymbolOptions wsOpts = new WorkspaceSymbolOptions(); wsOpts.setResolveProvider(true); @@ -920,7 +923,7 @@ public CompletableFuture initialize(InitializeParams init) { // but complete the InitializationRequest independently of the project initialization. return CompletableFuture.completedFuture( finishInitialization( - constructInitResponse(init, checkJavaSupport()) + constructInitResponse(init, checkJavaSupport(), capa) ) ); } @@ -947,13 +950,13 @@ private void initializeOptions() { ConfigurationItem item = new ConfigurationItem(); FileObject fo = projects[0].getProjectDirectory(); item.setScopeUri(Utils.toUri(fo)); - item.setSection(NETBEANS_FORMAT); + item.setSection(client.getNbCodeCapabilities().getConfigurationPrefix() + NETBEANS_FORMAT); client.configuration(new ConfigurationParams(Collections.singletonList(item))).thenAccept(c -> { if (c != null && !c.isEmpty() && c.get(0) instanceof JsonObject) { workspaceService.updateJavaFormatPreferences(fo, (JsonObject) c.get(0)); } }); - item.setSection(NETBEANS_JAVA_IMPORTS); + item.setSection(client.getNbCodeCapabilities().getConfigurationPrefix() + NETBEANS_JAVA_IMPORTS); client.configuration(new ConfigurationParams(Collections.singletonList(item))).thenAccept(c -> { if (c != null && !c.isEmpty() && c.get(0) instanceof JsonObject) { workspaceService.updateJavaImportPreferences(fo, (JsonObject) c.get(0)); @@ -1037,60 +1040,60 @@ public void setTrace(SetTraceParams params) { public static final String NBLS_BUILD_WORKSPACE = "nbls.build.workspace"; public static final String NBLS_CLEAN_WORKSPACE = "nbls.clean.workspace"; - public static final String JAVA_NEW_FROM_TEMPLATE = "java.new.from.template"; - public static final String JAVA_NEW_PROJECT = "java.new.project"; - public static final String JAVA_GET_PROJECT_SOURCE_ROOTS = "java.get.project.source.roots"; - public static final String JAVA_GET_PROJECT_CLASSPATH = "java.get.project.classpath"; - public static final String JAVA_GET_PROJECT_PACKAGES = "java.get.project.packages"; - public static final String JAVA_LOAD_WORKSPACE_TESTS = "java.load.workspace.tests"; - public static final String JAVA_RESOLVE_STACKTRACE_LOCATION = "java.resolve.stacktrace.location"; - public static final String JAVA_SUPER_IMPLEMENTATION = "java.super.implementation"; - public static final String GRAALVM_PAUSE_SCRIPT = "graalvm.pause.script"; - public static final String JAVA_RUN_PROJECT_ACTION = "java.project.run.action"; + public static final String NBLS_NEW_FROM_TEMPLATE = "nbls.new.from.template"; + public static final String NBLS_NEW_PROJECT = "nbls.new.project"; + public static final String JAVA_GET_PROJECT_SOURCE_ROOTS = "nbls.java.get.project.source.roots"; + public static final String JAVA_GET_PROJECT_CLASSPATH = "nbls.java.get.project.classpath"; + public static final String JAVA_GET_PROJECT_PACKAGES = "nbls.java.get.project.packages"; + public static final String NBLS_LOAD_WORKSPACE_TESTS = "nbls.load.workspace.tests"; + public static final String NBLS_RESOLVE_STACKTRACE_LOCATION = "nbls.resolve.stacktrace.location"; + public static final String JAVA_SUPER_IMPLEMENTATION = "nbls.java.super.implementation"; + public static final String NBLS_GRAALVM_PAUSE_SCRIPT = "nbls.graalvm.pause.script"; + public static final String NBLS_RUN_PROJECT_ACTION = "nbls.project.run.action"; public static final String NBLS_GET_ARCHIVE_FILE_CONTENT = "nbls.get.archive.file.content"; /** * Enumerates project configurations. */ - public static final String JAVA_FIND_PROJECT_CONFIGURATIONS = "java.project.configurations"; + public static final String NBLS_FIND_PROJECT_CONFIGURATIONS = "nbls.project.configurations"; /** * Enumerates attach debugger configurations. */ - public static final String JAVA_FIND_DEBUG_ATTACH_CONFIGURATIONS = "java.attachDebugger.configurations"; + public static final String JAVA_FIND_DEBUG_ATTACH_CONFIGURATIONS = "nbls.java.attachDebugger.configurations"; /** * Enumerates JVM processes eligible for debugger attach. */ - public static final String JAVA_FIND_DEBUG_PROCESS_TO_ATTACH = "java.attachDebugger.pickProcess"; + public static final String JAVA_FIND_DEBUG_PROCESS_TO_ATTACH = "nbls.java.attachDebugger.pickProcess"; /** * Enumerates native processes eligible for debugger attach. */ - public static final String NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH = "nativeImage.attachDebugger.pickProcess"; + public static final String NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH = "nbls.nativeImage.attachDebugger.pickProcess"; /** * Provides code-completion of configurations. */ - public static final String JAVA_PROJECT_CONFIGURATION_COMPLETION = "java.project.configuration.completion"; + public static final String NBLS_PROJECT_CONFIGURATION_COMPLETION = "nbls.project.configuration.completion"; /** * Provides resolution of project problems. */ - public static final String JAVA_PROJECT_RESOLVE_PROJECT_PROBLEMS = "java.project.resolveProjectProblems"; + public static final String NBLS_PROJECT_RESOLVE_PROJECT_PROBLEMS = "nbls.project.resolveProjectProblems"; /** * Diagnostic / test command: clears NBLS internal project caches. Useful between testcases and after * new project files were generated into workspace subtree. */ - public static final String JAVA_CLEAR_PROJECT_CACHES = "java.clear.project.caches"; + public static final String NBLS_CLEAR_PROJECT_CACHES = "nbls.clear.project.caches"; /** * For a project directory, returns basic project information and structure. * Syntax: nbls.project.info(locations : String | String[], options? : { projectStructure? : boolean; actions? : boolean; recursive? : boolean }) : LspProjectInfo */ - public static final String JAVA_PROJECT_INFO = "nbls.project.info"; + public static final String NBLS_PROJECT_INFO = "nbls.project.info"; /** * Provides enable preview for given project */ - public static final String JAVA_ENABLE_PREVIEW = "java.project.enable.preview"; + public static final String JAVA_ENABLE_PREVIEW = "nbls.java.project.enable.preview"; /** * Provides symbols for the given document diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java index d375067eee75..d893783f6995 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/SurroundWithHint.java @@ -80,7 +80,7 @@ public final class SurroundWithHint extends CodeActionsProvider { private static final String COMMAND_INSERT_SNIPPET = "editor.action.insertSnippet"; - private static final String COMMAND_SURROUND_WITH = "java.surround.with"; + private static final String COMMAND_SURROUND_WITH = "surround.with"; private static final String DOTS = "..."; private static final String SNIPPET = "snippet"; private static final String SELECTION_VAR = "${selection}"; @@ -96,7 +96,7 @@ public final class SurroundWithHint extends CodeActionsProvider { "DN_SurroundWith=Surround with {0}", "DN_SurroundWithAll=Surround with ...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { CompilationController info = resultIterator.getParserResult() != null ? CompilationController.get(resultIterator.getParserResult()) : null; if (info == null) { return Collections.emptyList(); @@ -134,7 +134,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction snippet = sb.append(snippet).toString(); } int idx = label.indexOf(' '); - CodeAction codeAction = createCodeAction(Bundle.DN_SurroundWith(idx < 0 ? label : label.substring(0, idx)), CodeActionKind.RefactorRewrite, null, COMMAND_INSERT_SNIPPET, Collections.singletonMap(SNIPPET, snippet)); + CodeAction codeAction = createCodeAction(client, Bundle.DN_SurroundWith(idx < 0 ? label : label.substring(0, idx)), CodeActionKind.RefactorRewrite, null, COMMAND_INSERT_SNIPPET, Collections.singletonMap(SNIPPET, snippet)); if (!edits.isEmpty()) { codeAction.setEdit(new WorkspaceEdit(Collections.singletonMap(params.getTextDocument().getUri(), edits))); } @@ -146,7 +146,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction } } if (items.size() > codeActions.size()) { - codeActions.add(createCodeAction(Bundle.DN_SurroundWithAll(), CodeActionKind.RefactorRewrite, null, COMMAND_SURROUND_WITH, items)); + codeActions.add(createCodeAction(client, Bundle.DN_SurroundWithAll(), CodeActionKind.RefactorRewrite, null, COMMAND_SURROUND_WITH, items)); } return codeActions; } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestClassGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestClassGenerator.java index 0df6ff065acf..3b20aa7b2de7 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestClassGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TestClassGenerator.java @@ -75,7 +75,7 @@ @ServiceProvider(service = CodeActionsProvider.class, position = 100) public final class TestClassGenerator extends CodeActionsProvider { - private static final String GENERATE_TEST_CLASS_COMMAND = "java.generate.testClass"; + private static final String GENERATE_TEST_CLASS_COMMAND = "nbls.java.generate.testClass"; @Override @NbBundle.Messages({ @@ -83,7 +83,7 @@ public final class TestClassGenerator extends CodeActionsProvider { "# {1} - the location where the test class will be created", "DN_GenerateTestClass=Create Test Class [{0} in {1}]" }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { CompilationController info = resultIterator.getParserResult() != null ? CompilationController.get(resultIterator.getParserResult()) : null; if (info == null) { return Collections.emptyList(); @@ -123,7 +123,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction for (Map.Entry> entrySet : validCombinations.entrySet()) { Object location = entrySet.getKey(); for (String testingFramework : entrySet.getValue()) { - result.add((createCodeAction(Bundle.DN_GenerateTestClass(testingFramework, getLocationText(location)), CodeActionKind.Refactor, null, GENERATE_TEST_CLASS_COMMAND, Utils.toUri(fileObject), testingFramework, Utils.toUri(getTargetFolder(location))))); + result.add((createCodeAction(client, Bundle.DN_GenerateTestClass(testingFramework, getLocationText(location)), CodeActionKind.Refactor, null, GENERATE_TEST_CLASS_COMMAND, Utils.toUri(fileObject), testingFramework, Utils.toUri(getTargetFolder(location))))); } } return result; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java index d1691690fe2b..8f71804dfcb9 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java @@ -266,10 +266,10 @@ public class TextDocumentServiceImpl implements TextDocumentService, LanguageClientAware { private static final Logger LOG = Logger.getLogger(TextDocumentServiceImpl.class.getName()); - private static final String COMMAND_RUN_SINGLE = "java.run.single"; // NOI18N - private static final String COMMAND_DEBUG_SINGLE = "java.debug.single"; // NOI18N - private static final String NETBEANS_JAVADOC_LOAD_TIMEOUT = "netbeans.javadoc.load.timeout";// NOI18N - private static final String NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS = "netbeans.java.onSave.organizeImports";// NOI18N + private static final String COMMAND_RUN_SINGLE = "nbls.run.single"; // NOI18N + private static final String COMMAND_DEBUG_SINGLE = "nbls.debug.single"; // NOI18N + private static final String NETBEANS_JAVADOC_LOAD_TIMEOUT = "javadoc.load.timeout";// NOI18N + private static final String NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS = "java.onSave.organizeImports";// NOI18N private static final String URL = "url";// NOI18N private static final String INDEX = "index";// NOI18N @@ -346,7 +346,7 @@ public CompletableFuture, CompletionList>> completio StyledDocument doc = (StyledDocument)rawDoc; ConfigurationItem conf = new ConfigurationItem(); conf.setScopeUri(uri); - conf.setSection(NETBEANS_JAVADOC_LOAD_TIMEOUT); + conf.setSection(client.getNbCodeCapabilities().getConfigurationPrefix() + NETBEANS_JAVADOC_LOAD_TIMEOUT); return client.configuration(new ConfigurationParams(Collections.singletonList(conf))).thenApply(c -> { if (c != null && !c.isEmpty()) { javadocTimeout.set(((JsonPrimitive)c.get(0)).getAsInt()); @@ -396,7 +396,7 @@ public CompletableFuture, CompletionList>> completio } org.netbeans.api.lsp.Command command = completion.getCommand(); if (command != null) { - item.setCommand(new Command(command.getTitle(), command.getCommand(), command.getArguments())); + item.setCommand(new Command(command.getTitle(), Utils.encodeCommand(command.getCommand(), client.getNbCodeCapabilities()), command.getArguments())); } if (completion.getAdditionalTextEdits() != null && completion.getAdditionalTextEdits().isDone()) { List additionalTextEdits = completion.getAdditionalTextEdits().getNow(null); @@ -1008,7 +1008,7 @@ public CompletableFuture>> codeAction(CodeActio commandParams.addAll(inputAction.getCommand().getArguments()); } - action.setCommand(new Command(inputAction.getCommand().getTitle(), inputAction.getCommand().getCommand(), commandParams)); + action.setCommand(new Command(inputAction.getCommand().getTitle(), Utils.encodeCommand(inputAction.getCommand().getCommand(), client.getNbCodeCapabilities()), commandParams)); } if (inputAction instanceof LazyCodeAction && ((LazyCodeAction) inputAction).getLazyEdit() != null) { lastCodeActions.add((LazyCodeAction) inputAction); @@ -1064,7 +1064,7 @@ public void run(ResultIterator resultIterator) throws Exception { //code generators: for (CodeActionsProvider codeGenerator : Lookup.getDefault().lookupAll(CodeActionsProvider.class)) { try { - for (CodeAction codeAction : codeGenerator.getCodeActions(resultIterator, params)) { + for (CodeAction codeAction : codeGenerator.getCodeActions(client, resultIterator, params)) { result.add(Either.forRight(codeAction)); } } catch (Exception ex) { @@ -1103,7 +1103,7 @@ public void run(ResultIterator resultIterator) throws Exception { codeAction.setEdit(new WorkspaceEdit(documentChanges)); int renameOffset = ((IntroduceFixBase) fix).getNameOffset(changes); if (renameOffset >= 0) { - codeAction.setCommand(new Command("Rename", "java.rename.element.at", Collections.singletonList(renameOffset))); + codeAction.setCommand(new Command("Rename", client.getNbCodeCapabilities().getCommandPrefix() + ".rename.element.at", Collections.singletonList(renameOffset))); } result.add(Either.forRight(codeAction)); } @@ -1215,7 +1215,7 @@ private List convertCodeLens(Document doc, List> willSaveWaitUntil(WillSaveTextDocumentP } ConfigurationItem conf = new ConfigurationItem(); conf.setScopeUri(uri); - conf.setSection(NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS); + conf.setSection(client.getNbCodeCapabilities().getConfigurationPrefix() + NETBEANS_JAVA_ON_SAVE_ORGANIZE_IMPORTS); return client.configuration(new ConfigurationParams(Collections.singletonList(conf))).thenApply(c -> { if (c != null && !c.isEmpty() && ((JsonPrimitive) c.get(0)).getAsBoolean()) { try { diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java index 223866044d71..1ce3788cc645 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/ToStringGenerator.java @@ -72,7 +72,7 @@ public final class ToStringGenerator extends CodeActionsProvider { @NbBundle.Messages({ "DN_GenerateToString=Generate toString()...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Source)) { return Collections.emptyList(); @@ -114,7 +114,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction data.put(URI, uri); data.put(OFFSET, offset); data.put(FIELDS, fields); - return Collections.singletonList(createCodeAction(Bundle.DN_GenerateToString(), CODE_GENERATOR_KIND, data, fields.isEmpty() ? null : "workbench.action.focusActiveEditorGroup")); + return Collections.singletonList(createCodeAction(client, Bundle.DN_GenerateToString(), CODE_GENERATOR_KIND, data, fields.isEmpty() ? null : "workbench.action.focusActiveEditorGroup")); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java index 8cebda5b814c..cdd7f6abed22 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/WorkspaceServiceImpl.java @@ -172,15 +172,15 @@ public final class WorkspaceServiceImpl implements WorkspaceService, LanguageCli @Override public CompletableFuture executeCommand(ExecuteCommandParams params) { - String command = params.getCommand(); + String command = Utils.decodeCommand(params.getCommand(), client.getNbCodeCapabilities()); switch (command) { - case Server.GRAALVM_PAUSE_SCRIPT: + case Server.NBLS_GRAALVM_PAUSE_SCRIPT: ActionsManager am = DebuggerManager.getDebuggerManager().getCurrentEngine().getActionsManager(); am.doAction("pauseInGraalScript"); return CompletableFuture.completedFuture(true); - case Server.JAVA_NEW_FROM_TEMPLATE: + case Server.NBLS_NEW_FROM_TEMPLATE: return LspTemplateUI.createFromTemplate("Templates", client, params); - case Server.JAVA_NEW_PROJECT: + case Server.NBLS_NEW_PROJECT: return LspTemplateUI.createProject("Templates/Project", client, params); case Server.NBLS_BUILD_WORKSPACE: { final CommandProgress progressOfCompilation = new CommandProgress(); @@ -194,7 +194,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { progressOfCompilation.checkStatus(); return progressOfCompilation.getFinishFuture(); } - case Server.JAVA_RUN_PROJECT_ACTION: { + case Server.NBLS_RUN_PROJECT_ACTION: { // TODO: maybe a structure would be better for future compatibility / extensions, i.e. what to place in the action's context Lookup. List targets = new ArrayList<>(); ProjectActionParams actionParams = gson.fromJson(gson.toJson(params.getArguments().get(0)), ProjectActionParams.class); @@ -337,7 +337,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return future; }); } - case Server.JAVA_LOAD_WORKSPACE_TESTS: { + case Server.NBLS_LOAD_WORKSPACE_TESTS: { String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString(); FileObject file; try { @@ -420,7 +420,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return future; }); } - case Server.JAVA_RESOLVE_STACKTRACE_LOCATION: { + case Server.NBLS_RESOLVE_STACKTRACE_LOCATION: { CompletableFuture future = new CompletableFuture<>(); try { if (params.getArguments().size() >= 3) { @@ -467,7 +467,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { String uri = ((JsonPrimitive) params.getArguments().get(0)).getAsString(); Position pos = gson.fromJson(gson.toJson(params.getArguments().get(1)), Position.class); return (CompletableFuture)((TextDocumentServiceImpl)server.getTextDocumentService()).superImplementations(uri, pos); - case Server.JAVA_FIND_PROJECT_CONFIGURATIONS: { + case Server.NBLS_FIND_PROJECT_CONFIGURATIONS: { String fileUri = ((JsonPrimitive) params.getArguments().get(0)).getAsString(); FileObject file; @@ -481,7 +481,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return findProjectConfigurations(file); } case Server.JAVA_FIND_DEBUG_ATTACH_CONFIGURATIONS: { - return AttachConfigurations.findConnectors(); + return AttachConfigurations.findConnectors(client.getNbCodeCapabilities()); } case Server.JAVA_FIND_DEBUG_PROCESS_TO_ATTACH: { return AttachConfigurations.findProcessAttachTo(client); @@ -489,7 +489,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { case Server.NATIVE_IMAGE_FIND_DEBUG_PROCESS_TO_ATTACH: { return AttachNativeConfigurations.findProcessAttachTo(client); } - case Server.JAVA_PROJECT_CONFIGURATION_COMPLETION: { + case Server.NBLS_PROJECT_CONFIGURATION_COMPLETION: { // We expect one, two or three arguments. // The first argument is always the URI of the launch.json file. // When not more arguments are provided, all available configurations ought to be provided. @@ -497,7 +497,11 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { // and additional attributes valid in that particular configuration ought to be provided. // When a third argument is present, it's an attribute name whose possible values ought to be provided. List arguments = params.getArguments(); - Collection configurations = Lookup.getDefault().lookupAll(LaunchConfigurationCompletion.class); + Collection configurations = Lookup.getDefault() + .lookupAll(LaunchConfigurationCompletion.Factory.class) + .stream() + .map(f -> f.createLaunchConfigurationCompletion(client.getNbCodeCapabilities())) + .collect(Collectors.toList()); List>> completionFutures; String configUri = ((JsonPrimitive) arguments.get(0)).getAsString(); Supplier> projectSupplier = () -> { @@ -534,7 +538,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { .thenApply(avoid -> completionFutures.stream().flatMap(c -> c.join().stream()).collect(Collectors.toList())); return (CompletableFuture) (CompletableFuture) joinedFuture; } - case Server.JAVA_PROJECT_RESOLVE_PROJECT_PROBLEMS: { + case Server.NBLS_PROJECT_RESOLVE_PROJECT_PROBLEMS: { final CompletableFuture result = new CompletableFuture<>(); List arguments = params.getArguments(); if (!arguments.isEmpty()) { @@ -590,7 +594,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { } return result; } - case Server.JAVA_CLEAR_PROJECT_CACHES: { + case Server.NBLS_CLEAR_PROJECT_CACHES: { // politely clear project manager's cache of "no project" answers ProjectManager.getDefault().clearNonProjectCache(); // impolitely clean the project-based traversal's cache, so any affiliation of intermediate folders will disappear @@ -614,7 +618,7 @@ public CompletableFuture executeCommand(ExecuteCommandParams params) { return (CompletableFuture) (CompletableFuture)result; } - case Server.JAVA_PROJECT_INFO: { + case Server.NBLS_PROJECT_INFO: { final CompletableFuture result = new CompletableFuture<>(); List arguments = params.getArguments(); if (arguments.size() < 1) { @@ -1256,17 +1260,24 @@ private static String getSimpleName ( @Override public void didChangeConfiguration(DidChangeConfigurationParams params) { + String fullConfigPrefix = client.getNbCodeCapabilities().getConfigurationPrefix(); + String configPrefix = fullConfigPrefix.substring(0, fullConfigPrefix.length() - 1); server.openedProjects().thenAccept(projects -> { if (projects != null && projects.length > 0) { - updateJavaFormatPreferences(projects[0].getProjectDirectory(), ((JsonObject) params.getSettings()).getAsJsonObject("netbeans").getAsJsonObject("format")); - updateJavaImportPreferences(projects[0].getProjectDirectory(), ((JsonObject) params.getSettings()).getAsJsonObject("netbeans").getAsJsonObject("java").getAsJsonObject("imports")); + updateJavaFormatPreferences(projects[0].getProjectDirectory(), ((JsonObject) params.getSettings()).getAsJsonObject(configPrefix).getAsJsonObject("format")); + updateJavaImportPreferences(projects[0].getProjectDirectory(), ((JsonObject) params.getSettings()).getAsJsonObject(configPrefix).getAsJsonObject("java").getAsJsonObject("imports")); } }); + String fullAltConfigPrefix = client.getNbCodeCapabilities().getAltConfigurationPrefix(); + String altConfigPrefix = fullConfigPrefix.substring(0, fullAltConfigPrefix.length() - 1); boolean modified = false; String newVMOptions = ""; - JsonObject javaPlus = ((JsonObject) params.getSettings()).getAsJsonObject("java+"); + JsonObject javaPlus = ((JsonObject) params.getSettings()).getAsJsonObject(altConfigPrefix); if (javaPlus != null) { - newVMOptions = javaPlus.getAsJsonObject("runConfig").getAsJsonPrimitive("vmOptions").getAsString(); + JsonObject runConfig = javaPlus.getAsJsonObject("runConfig"); + if (runConfig != null) { + newVMOptions = runConfig.getAsJsonPrimitive("vmOptions").getAsString(); + } } for (CompilerOptionsQueryImpl query : Lookup.getDefault().lookupAll(CompilerOptionsQueryImpl.class)) { modified |= query.setConfiguration(client, newVMOptions); diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java index e00d42b891ed..ecba2107a267 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ChangeMethodParametersRefactoring.java @@ -77,7 +77,7 @@ public final class ChangeMethodParametersRefactoring extends CodeRefactoring { private static final String CHANGE_METHOD_PARAMS_REFACTORING_KIND = "refactor.change.method.params"; - private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "java.refactor.change.method.params"; + private static final String CHANGE_METHOD_PARAMS_REFACTORING_COMMAND = "nbls.java.refactor.change.method.params"; private final Gson gson = new Gson(); @@ -85,7 +85,7 @@ public final class ChangeMethodParametersRefactoring extends CodeRefactoring { @NbBundle.Messages({ "DN_ChangeMethodParams=Change Method Parameters...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Refactor)) { return Collections.emptyList(); @@ -125,7 +125,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction } QuickPickItem elementItem = new QuickPickItem(createLabel(info, element, true)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, null, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); + return Collections.singletonList(createCodeAction(client, Bundle.DN_ChangeMethodParams(), CHANGE_METHOD_PARAMS_REFACTORING_KIND, null, CHANGE_METHOD_PARAMS_REFACTORING_COMMAND, Utils.toUri(elementSource), elementItem)); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java index 8b434156f086..fc0dbf8651b7 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/ExtractSuperclassOrInterfaceRefactoring.java @@ -79,8 +79,8 @@ @ServiceProvider(service = CodeActionsProvider.class, position = 170) public final class ExtractSuperclassOrInterfaceRefactoring extends CodeRefactoring { - private static final String EXTRACT_SUPERCLASS_REFACTORING_COMMAND = "java.refactor.extract.superclass"; - private static final String EXTRACT_INTERFACE_REFACTORING_COMMAND = "java.refactor.extract.interface"; + private static final String EXTRACT_SUPERCLASS_REFACTORING_COMMAND = "nbls.java.refactor.extract.superclass"; + private static final String EXTRACT_INTERFACE_REFACTORING_COMMAND = "nbls.java.refactor.extract.interface"; private static final ClassPath EMPTY_PATH = ClassPathSupport.createClassPath(new URL[0]); private final Set commands = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(EXTRACT_INTERFACE_REFACTORING_COMMAND, EXTRACT_SUPERCLASS_REFACTORING_COMMAND))); @@ -91,7 +91,7 @@ public final class ExtractSuperclassOrInterfaceRefactoring extends CodeRefactori "DN_ExtractSuperclass=Extract Superclass...", "DN_ExtractInterface=Extract Interface...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Refactor)) { return Collections.emptyList(); @@ -158,10 +158,10 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction QuickPickItem elementItem = new QuickPickItem(createLabel(info, type)); elementItem.setUserData(new ElementData(type)); if (!type.getKind().isInterface()) { - result.add(createCodeAction(Bundle.DN_ExtractSuperclass(), CodeActionKind.RefactorExtract, null, EXTRACT_SUPERCLASS_REFACTORING_COMMAND, uri, elementItem, allMembers)); + result.add(createCodeAction(client, Bundle.DN_ExtractSuperclass(), CodeActionKind.RefactorExtract, null, EXTRACT_SUPERCLASS_REFACTORING_COMMAND, uri, elementItem, allMembers)); } if (!members.isEmpty()) { - result.add(createCodeAction(Bundle.DN_ExtractInterface(), CodeActionKind.RefactorExtract, null, EXTRACT_INTERFACE_REFACTORING_COMMAND, uri, elementItem, members)); + result.add(createCodeAction(client, Bundle.DN_ExtractInterface(), CodeActionKind.RefactorExtract, null, EXTRACT_INTERFACE_REFACTORING_COMMAND, uri, elementItem, members)); } } return result; diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java index 9890157d1944..64a776fffe2f 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/MoveRefactoring.java @@ -99,7 +99,7 @@ public final class MoveRefactoring extends CodeRefactoring { private static final String MOVE_REFACTORING_KIND = "refactor.move"; - private static final String MOVE_REFACTORING_COMMAND = "java.refactor.move"; + private static final String MOVE_REFACTORING_COMMAND = "nbls.java.refactor.move"; private static final ClassPath EMPTY_PATH = ClassPathSupport.createClassPath(new URL[0]); private final Gson gson = new Gson(); @@ -108,7 +108,7 @@ public final class MoveRefactoring extends CodeRefactoring { @NbBundle.Messages({ "DN_Move=Move...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Refactor)) { return Collections.emptyList(); @@ -127,9 +127,9 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction String uri = Utils.toUri(info.getFileObject()); Element element = elementForOffset(info, offset); if (element != null) { - return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri, new ElementData(element))); + return Collections.singletonList(createCodeAction(client, Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri, new ElementData(element))); } else { - return Collections.singletonList(createCodeAction(Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri)); + return Collections.singletonList(createCodeAction(client, Bundle.DN_Move(), MOVE_REFACTORING_KIND, null, MOVE_REFACTORING_COMMAND, uri)); } } diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java index c30be2e2467a..c428a19b1011 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PullUpRefactoring.java @@ -76,7 +76,7 @@ public final class PullUpRefactoring extends CodeRefactoring { private static final String PULL_UP_REFACTORING_KIND = "refactor.pull.up"; - private static final String PULL_UP_REFACTORING_COMMAND = "java.refactor.pull.up"; + private static final String PULL_UP_REFACTORING_COMMAND = "nbls.java.refactor.pull.up"; private final Gson gson = new Gson(); @@ -84,7 +84,7 @@ public final class PullUpRefactoring extends CodeRefactoring { @NbBundle.Messages({ "DN_PullUp=Pull Up...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Refactor)) { return Collections.emptyList(); @@ -125,7 +125,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction } QuickPickItem elementItem = new QuickPickItem(createLabel(info, element)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_PullUp(), PULL_UP_REFACTORING_KIND, null, PULL_UP_REFACTORING_COMMAND, uri, offset, elementItem, supertypeItems)); + return Collections.singletonList(createCodeAction(client, Bundle.DN_PullUp(), PULL_UP_REFACTORING_KIND, null, PULL_UP_REFACTORING_COMMAND, uri, offset, elementItem, supertypeItems)); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java index 0f8dd2e18abb..89dc2591ef2f 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/refactoring/PushDownRefactoring.java @@ -72,7 +72,7 @@ public final class PushDownRefactoring extends CodeRefactoring { private static final String PUSH_DOWN_REFACTORING_KIND = "refactor.push.down"; - private static final String PUSH_DOWN_REFACTORING_COMMAND = "java.refactor.push.down"; + private static final String PUSH_DOWN_REFACTORING_COMMAND = "nbls.java.refactor.push.down"; private final Gson gson = new Gson(); @@ -80,7 +80,7 @@ public final class PushDownRefactoring extends CodeRefactoring { @NbBundle.Messages({ "DN_PushDown=Push Down...", }) - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { List only = params.getContext().getOnly(); if (only == null || !only.contains(CodeActionKind.Refactor)) { return Collections.emptyList(); @@ -136,7 +136,7 @@ public List getCodeActions(ResultIterator resultIterator, CodeAction } QuickPickItem elementItem = new QuickPickItem(createLabel(info, element)); elementItem.setUserData(new ElementData(element)); - return Collections.singletonList(createCodeAction(Bundle.DN_PushDown(), PUSH_DOWN_REFACTORING_KIND, null, PUSH_DOWN_REFACTORING_COMMAND, uri, elementItem, members)); + return Collections.singletonList(createCodeAction(client, Bundle.DN_PushDown(), PUSH_DOWN_REFACTORING_KIND, null, PUSH_DOWN_REFACTORING_COMMAND, uri, elementItem, members)); } @Override diff --git a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/singlesourcefile/EnablePreviewSingleSourceFile.java b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/singlesourcefile/EnablePreviewSingleSourceFile.java index 562f9fc32824..019e46d782d9 100644 --- a/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/singlesourcefile/EnablePreviewSingleSourceFile.java +++ b/java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/singlesourcefile/EnablePreviewSingleSourceFile.java @@ -65,7 +65,7 @@ public void enablePreview(String newSourceLevel) throws Exception { ConfigurationItem conf = new ConfigurationItem(); conf.setScopeUri(Utils.toUri(file)); - conf.setSection("java+.runConfig.vmOptions"); //XXX + conf.setSection(client.getNbCodeCapabilities().getAltConfigurationPrefix() + "runConfig.vmOptions"); client.configuration(new ConfigurationParams(Collections.singletonList(conf))).thenApply(c -> { String compilerArgs = ((JsonPrimitive) ((List) c).get(0)).getAsString(); if (compilerArgs == null) { @@ -84,7 +84,7 @@ public void enablePreview(String newSourceLevel) throws Exception { } else { compilerArgs += (compilerArgs.isEmpty() ? "" : " ") + ENABLE_PREVIEW_FLAG + " " + SOURCE_FLAG + " " + realNewSourceLevel; } - client.configurationUpdate(new UpdateConfigParams("java+.runConfig", "vmOptions", compilerArgs)); + client.configurationUpdate(new UpdateConfigParams(client.getNbCodeCapabilities().getAltConfigurationPrefix() + "runConfig", "vmOptions", compilerArgs)); return null; }); } diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/explorer/ProjectViewTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/explorer/ProjectViewTest.java index 9c1d2aac8fe1..060c4c6200a7 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/explorer/ProjectViewTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/explorer/ProjectViewTest.java @@ -358,7 +358,7 @@ private TreeItem createAndFindProjectNode() throws Exception { public class ServerLookupExtractionCommand extends CodeActionsProvider { @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } diff --git a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java index 8f657a9b2bbd..eb830b02d1cf 100644 --- a/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java +++ b/java/java.lsp.server/test/unit/src/org/netbeans/modules/java/lsp/server/protocol/ServerTest.java @@ -241,7 +241,7 @@ public ServerLookupExtractionCommand() { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } @@ -2623,7 +2623,7 @@ public CompletableFuture applyEdit(ApplyWorkspaceEdi fileChanges.get(3).getNewText()); Command command = introduceVariable.get().getCommand(); assertNotNull(command); - assertEquals("java.rename.element.at", command.getCommand()); + assertEquals("nbls.rename.element.at", command.getCommand()); List arguments = command.getArguments(); assertNotNull(arguments); assertEquals(1, arguments.size()); @@ -2726,7 +2726,7 @@ public CompletableFuture applyEdit(ApplyWorkspaceEdi fileChanges.get(2).getNewText()); Command command = introduceConstant.get().getCommand(); assertNotNull(command); - assertEquals("java.rename.element.at", command.getCommand()); + assertEquals("nbls.rename.element.at", command.getCommand()); List arguments = command.getArguments(); assertNotNull(arguments); assertEquals(1, arguments.size()); @@ -2829,7 +2829,7 @@ public CompletableFuture applyEdit(ApplyWorkspaceEdi fileChanges.get(2).getNewText()); Command command = introduceField.get().getCommand(); assertNotNull(command); - assertEquals("java.rename.element.at", command.getCommand()); + assertEquals("nbls.rename.element.at", command.getCommand()); List arguments = command.getArguments(); assertNotNull(arguments); assertEquals(1, arguments.size()); @@ -2935,7 +2935,7 @@ public CompletableFuture applyEdit(ApplyWorkspaceEdi fileChanges.get(2).getNewText()); Command command = introduceMethod.get().getCommand(); assertNotNull(command); - assertEquals("java.rename.element.at", command.getCommand()); + assertEquals("nbls.rename.element.at", command.getCommand()); List arguments = command.getArguments(); assertNotNull(arguments); assertEquals(1, arguments.size()); @@ -5459,7 +5459,7 @@ public ProgressCommand() { } @Override - public List getCodeActions(ResultIterator resultIterator, CodeActionParams params) throws Exception { + public List getCodeActions(NbCodeLanguageClient client, ResultIterator resultIterator, CodeActionParams params) throws Exception { return Collections.emptyList(); } @@ -5500,7 +5500,7 @@ public CompletableFuture processCommand(NbCodeLanguageClient client, Str @Override public Set getCommands() { - return Collections.singleton("_progressCommand"); + return Collections.singleton("test._progressCommand"); } @@ -5570,7 +5570,7 @@ public void showMessage(MessageParams params) { // now invoke the build ExecuteCommandParams ecp = new ExecuteCommandParams(); - ecp.setCommand("_progressCommand"); + ecp.setCommand("test._progressCommand"); CompletableFuture buildF = server.getWorkspaceService().executeCommand(ecp); // the progress must be received at the client w/ the token, we need the token to issue cancel diff --git a/java/java.lsp.server/vscode/package.json b/java/java.lsp.server/vscode/package.json index 52534721824f..b9f9a23fb299 100644 --- a/java/java.lsp.server/vscode/package.json +++ b/java/java.lsp.server/vscode/package.json @@ -87,7 +87,7 @@ "viewsWelcome": [ { "view": "database.connections", - "contents": "No database connections found.\n[Add Database Connection](command:db.add.connection)\n[Add Oracle Autonomous DB](command:nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddADBAction)", + "contents": "No database connections found.\n[Add Database Connection](command:nbls.db.add.connection)\n[Add Oracle Autonomous DB](command:nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddADBAction)", "when": "nb.database.view.active" } ], @@ -323,7 +323,7 @@ }, "processId": { "type": "string", - "default": "${command:java.attachDebugger.pickProcess}", + "default": "${command:nbls.java.attachDebugger.pickProcess}", "description": "Process Id of the debuggee" }, "listen": { @@ -400,7 +400,7 @@ }, "processId": { "type": "string", - "default": "${command:nativeImage.attachDebugger.pickProcess}", + "default": "${command:nbls.nativeImage.attachDebugger.pickProcess}", "description": "Process Id of the native image" }, "miDebugger": { @@ -437,7 +437,7 @@ "type": "nativeimage", "request": "attach", "name": "Attach to Native Image", - "processId": "^\"\\${command:nativeImage.attachDebugger.pickProcess\\}\"", + "processId": "^\"\\${command:nbls.nativeImage.attachDebugger.pickProcess\\}\"", "nativeImagePath": "" } } @@ -460,44 +460,44 @@ "category": "Java" }, { - "command": "java.workspace.new", + "command": "nbls.workspace.new", "title": "New from Template...", "category": "Java", "icon": "$(new-file)" }, { - "command": "java.workspace.newproject", + "command": "nbls.workspace.newproject", "title": "New Project...", "category": "Java", "icon": "$(new-folder)" }, { - "command": "java.goto.super.implementation", + "command": "nbls.java.goto.super.implementation", "title": "Go to Super Implementation", "category": "Java" }, { - "command": "java.open.type", + "command": "nbls.open.type", "title": "Open Type...", "category": "Java" }, { - "command": "graalvm.pause.script", + "command": "nbls.graalvm.pause.script", "title": "Pause in Script", "category": "GraalVM" }, { - "command": "foundProjects.deleteEntry", + "command": "nbls.foundProjects.deleteEntry", "title": "Delete" }, { - "command": "db.add.all.connection", + "command": "nbls.db.add.all.connection", "title": "Add Database Connection", "category": "Database", "icon": "$(add)" }, { - "command": "db.add.connection", + "command": "nbls.db.add.connection", "title": "Add JDBC Database Connection" }, { @@ -537,57 +537,42 @@ "title": "Delete" }, { - "command": "workbench.action.debug.run", - "title": "Run Without Debugging", - "icon": "$(run)" - }, - { - "command": "workbench.action.debug.start", - "title": "Start Debugging", - "icon": "$(debug-alt)" - }, - { - "command": "java.project.run", + "command": "nbls.project.run", "category": "Project", "title": "Run Project Without Debugging", "icon": "$(run)" }, { - "command": "java.project.debug", + "command": "nbls.project.debug", "category": "Project", "title": "Debug Project", "icon": "$(debug-alt)" }, { - "command": "java.project.test", + "command": "nbls.project.test", "category": "Project", "title": "Test Project", "icon": "$(testing-run-all-icon)" }, { - "command": "java.project.compile", + "command": "nbls.project.compile", "category": "Project", "title": "Compile Project" }, { - "command": "java.project.clean", + "command": "nbls.project.clean", "category": "Project", "title": "Clean Project" }, { - "command": "java.local.db.set.preferred.connection", + "command": "nbls.local.db.set.preferred.connection", "title": "Set as Default Connection" }, { - "command": "java.workspace.configureRunSettings", + "command": "nbls.workspace.configureRunSettings", "title": "Edit", "icon": "$(edit)" }, - { - "command": "testing.runAll", - "title": "Run All Tests", - "category": "Test" - }, { "command": "nbls.addEventListener", "title": "Add event listener" @@ -613,9 +598,24 @@ "title": "Add to OCI Vault" }, { - "command": "java.select.editor.projects", + "command": "nbls.select.editor.projects", "title": "Reveal active editor in Projects", "category": "Project" + }, + { + "command": "workbench.action.debug.run", + "title": "Run Without Debugging", + "icon": "$(run)" + }, + { + "command": "workbench.action.debug.start", + "title": "Start Debugging", + "icon": "$(debug-alt)" + }, + { + "command": "testing.runAll", + "title": "Run All Tests", + "category": "Test" } ], "keybindings": [ @@ -625,7 +625,7 @@ "when": "nbJavaLSReady && config.netbeans.javaSupport.enabled" }, { - "command": "java.goto.super.implementation", + "command": "nbls.java.goto.super.implementation", "key": "alt+U", "mac": "alt+cmd+U", "when": "editorHasCodeActionsProvider && editorTextFocus && config.netbeans.javaSupport.enabled" @@ -640,25 +640,25 @@ "menus": { "editor/context": [ { - "command": "java.goto.super.implementation", + "command": "nbls.java.goto.super.implementation", "when": "nbJavaLSReady && editorLangId == java && editorTextFocus && config.netbeans.javaSupport.enabled", "group": "navigation@100" } ], "explorer/context": [ { - "command": "java.workspace.new", + "command": "nbls.workspace.new", "when": "nbJavaLSReady && explorerResourceIsFolder", "group": "navigation@3" } ], "commandPalette": [ { - "command": "java.workspace.new", + "command": "nbls.workspace.new", "when": "nbJavaLSReady" }, { - "command": "java.workspace.newproject", + "command": "nbls.workspace.newproject", "when": "config.netbeans.javaSupport.enabled" }, { @@ -666,15 +666,15 @@ "when": "nbJavaLSReady && config.netbeans.javaSupport.enabled" }, { - "command": "java.goto.super.implementation", + "command": "nbls.java.goto.super.implementation", "when": "nbJavaLSReady && editorLangId == java && config.netbeans.javaSupport.enabled" }, { - "command": "graalvm.pause.script", + "command": "nbls.graalvm.pause.script", "when": "nbJavaLSReady" }, { - "command": "foundProjects.deleteEntry", + "command": "nbls.foundProjects.deleteEntry", "when": "false" }, { @@ -714,7 +714,7 @@ "when": "false" }, { - "command": "java.local.db.set.preferred.connection", + "command": "nbls.local.db.set.preferred.connection", "when": "false" }, { @@ -734,11 +734,11 @@ "when": "false" }, { - "command": "java.workspace.configureRunSettings", + "command": "nbls.workspace.configureRunSettings", "when": "false" }, { - "command": "db.add.all.connection", + "command": "nbls.db.add.all.connection", "when": "false" }, { @@ -748,7 +748,7 @@ ], "view/title": [ { - "command": "java.workspace.newproject", + "command": "nbls.workspace.newproject", "when": "nbJavaLSReady && view == foundProjects && config.netbeans.javaSupport.enabled", "group": "navigation" }, @@ -773,14 +773,14 @@ "when": "nbJavaLSReady && view == foundProjects && config.netbeans.javaSupport.enabled" }, { - "command": "db.add.all.connection", + "command": "nbls.db.add.all.connection", "when": "view == database.connections", "group": "navigation@3" } ], "view/item/context": [ { - "command": "foundProjects.deleteEntry", + "command": "nbls.foundProjects.deleteEntry", "when": "view == foundProjects && viewItem == node && config.netbeans.javaSupport.enabled" }, { @@ -809,37 +809,37 @@ "group": "db@50" }, { - "command": "java.workspace.new", + "command": "nbls.workspace.new", "when": "view == foundProjects && viewItem =~ /is:folder/", "group": "inline@1" }, { - "command": "java.project.run", + "command": "nbls.project.run", "when": "view == foundProjects && viewItem =~ /is:project/ && viewItem =~ /^(?!.*is:projectRoot)/ && config.netbeans.javaSupport.enabled", "group": "inline@10" }, { - "command": "java.project.debug", + "command": "nbls.project.debug", "when": "view == foundProjects && viewItem =~ /is:project/ && viewItem =~ /^(?!.*is:projectRoot)/ && config.netbeans.javaSupport.enabled", "group": "inline@11" }, { - "command": "java.project.test", + "command": "nbls.project.test", "when": "view == foundProjects && viewItem =~ /is:project/ && viewItem =~ /^(?!.*is:projectRoot)/ && config.netbeans.javaSupport.enabled", "group": "F@30" }, { - "command": "java.project.compile", + "command": "nbls.project.compile", "when": "view == foundProjects && viewItem =~ /is:project/ && config.netbeans.javaSupport.enabled", "group": "F@10" }, { - "command": "java.project.clean", + "command": "nbls.project.clean", "when": "view == foundProjects && viewItem =~ /is:project/ && config.netbeans.javaSupport.enabled", "group": "F@20" }, { - "command": "java.local.db.set.preferred.connection", + "command": "nbls.local.db.set.preferred.connection", "when": "viewItem =~ /class:org.netbeans.api.db.explorer.DatabaseConnection/", "group": "db@40" }, @@ -880,7 +880,7 @@ "group": "inline@13" }, { - "command": "java.workspace.configureRunSettings", + "command": "nbls.workspace.configureRunSettings", "when": "view == run-config && viewItem == configureRunSettings", "group": "inline@1" } diff --git a/java/java.lsp.server/vscode/src/dbConfigurationProvider.ts b/java/java.lsp.server/vscode/src/dbConfigurationProvider.ts index 74fcca86c076..91a4e6ce0221 100644 --- a/java/java.lsp.server/vscode/src/dbConfigurationProvider.ts +++ b/java/java.lsp.server/vscode/src/dbConfigurationProvider.ts @@ -44,7 +44,7 @@ class DBConfigurationProvider implements vscode.DebugConfigurationProvider { resolveDebugConfigurationWithSubstitutedVariables?(_folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, _token?: vscode.CancellationToken): vscode.ProviderResult { return new Promise(async resolve => { - let o: Object = await vscode.commands.executeCommand('java.db.connection'); + let o: Object = await vscode.commands.executeCommand('nbls.db.connection'); if (config === undefined) { config = {} as vscode.DebugConfiguration; } @@ -70,4 +70,4 @@ export function onDidTerminateSession(session: vscode.DebugSession): any { } } -export const dBConfigurationProvider = new DBConfigurationProvider(); \ No newline at end of file +export const dBConfigurationProvider = new DBConfigurationProvider(); diff --git a/java/java.lsp.server/vscode/src/extension.ts b/java/java.lsp.server/vscode/src/extension.ts index 4733e20e1dbf..29a6ac1ed5fa 100644 --- a/java/java.lsp.server/vscode/src/extension.ts +++ b/java/java.lsp.server/vscode/src/extension.ts @@ -63,6 +63,7 @@ import { env } from 'process'; import { PropertiesView } from './propertiesView/propertiesView'; const API_VERSION : string = "1.0"; +export const COMMAND_PREFIX : string = "nbls"; const DATABASE: string = 'Database'; const listeners = new Map(); let client: Promise; @@ -263,7 +264,7 @@ function wrapProjectActionWithProgress(action : string, configuration : string | items.push(item); } } - return wrapCommandWithProgress('java.project.run.action', title, log, showOutput, actionParams, ...items); + return wrapCommandWithProgress(COMMAND_PREFIX + '.project.run.action', title, log, showOutput, actionParams, ...items); } function wrapCommandWithProgress(lsCommand : string, title : string, log? : vscode.OutputChannel, showOutput? : boolean, ...args : any[]) : Thenable { @@ -433,7 +434,7 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java+', runConfigurationProvider)); context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('java', runConfigurationProvider)); context.subscriptions.push(vscode.window.registerTreeDataProvider('run-config', runConfigurationNodeProvider)); - context.subscriptions.push(vscode.commands.registerCommand('java.workspace.configureRunSettings', (...params: any[]) => { + context.subscriptions.push(vscode.commands.registerCommand(COMMAND_PREFIX + '.workspace.configureRunSettings', (...params: any[]) => { configureRunSettings(context, params); })); vscode.commands.executeCommand('setContext', 'runConfigurationInitialized', true); @@ -441,12 +442,12 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { }); // register commands - context.subscriptions.push(commands.registerCommand('java.workspace.new', async (ctx) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.new', async (ctx) => { let c : LanguageClient = await client; const commands = await vscode.commands.getCommands(); - if (commands.includes('java.new.from.template')) { + if (commands.includes(COMMAND_PREFIX + '.new.from.template')) { // first give the context, then the open-file hint in the case the context is not specific enough - const res = await vscode.commands.executeCommand('java.new.from.template', contextUri(ctx)?.toString(), vscode.window.activeTextEditor?.document?.uri?.toString()); + const res = await vscode.commands.executeCommand(COMMAND_PREFIX + '.new.from.template', contextUri(ctx)?.toString(), vscode.window.activeTextEditor?.document?.uri?.toString()); if (typeof res === 'string') { let newFile = vscode.Uri.parse(res as string); @@ -463,11 +464,11 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { throw `Client ${c} doesn't support new from template`; } })); - context.subscriptions.push(commands.registerCommand('java.workspace.newproject', async (ctx) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.newproject', async (ctx) => { let c : LanguageClient = await client; const commands = await vscode.commands.getCommands(); - if (commands.includes('java.new.project')) { - const res = await vscode.commands.executeCommand('java.new.project', contextUri(ctx)?.toString()); + if (commands.includes(COMMAND_PREFIX + '.new.project')) { + const res = await vscode.commands.executeCommand(COMMAND_PREFIX + '.new.project', contextUri(ctx)?.toString()); if (typeof res === 'string') { let newProject = vscode.Uri.parse(res as string); @@ -485,35 +486,35 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { throw `Client ${c} doesn't support new project`; } })); - context.subscriptions.push(commands.registerCommand('nbls.workspace.compile', () => - wrapCommandWithProgress('nbls.build.workspace', 'Compiling workspace...', log, true) + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.compile', () => + wrapCommandWithProgress(COMMAND_PREFIX + '.build.workspace', 'Compiling workspace...', log, true) )); - context.subscriptions.push(commands.registerCommand('nbls.workspace.clean', () => - wrapCommandWithProgress('nbls.clean.workspace', 'Cleaning workspace...', log, true) + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.clean', () => + wrapCommandWithProgress(COMMAND_PREFIX + '.clean.workspace', 'Cleaning workspace...', log, true) )); - context.subscriptions.push(commands.registerCommand('java.project.compile', (args) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.project.compile', (args) => { wrapProjectActionWithProgress('build', undefined, 'Compiling...', log, true, args); })); - context.subscriptions.push(commands.registerCommand('java.project.clean', (args) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.project.clean', (args) => { wrapProjectActionWithProgress('clean', undefined, 'Cleaning...', log, true, args); })); - context.subscriptions.push(commands.registerCommand('java.open.type', () => { - wrapCommandWithProgress('java.quick.open', 'Opening type...', log, true).then(() => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.open.type', () => { + wrapCommandWithProgress(COMMAND_PREFIX + '.quick.open', 'Opening type...', log, true).then(() => { commands.executeCommand('workbench.action.focusActiveEditorGroup'); }); })); - context.subscriptions.push(commands.registerCommand('java.goto.super.implementation', async () => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.java.goto.super.implementation', async () => { if (window.activeTextEditor?.document.languageId !== "java") { return; } const uri = window.activeTextEditor.document.uri; const position = window.activeTextEditor.selection.active; - const locations: any[] = await vscode.commands.executeCommand('java.super.implementation', uri.toString(), position) || []; + const locations: any[] = await vscode.commands.executeCommand(COMMAND_PREFIX + '.java.super.implementation', uri.toString(), position) || []; return vscode.commands.executeCommand('editor.action.goToLocations', window.activeTextEditor.document.uri, position, locations.map(location => new vscode.Location(vscode.Uri.parse(location.uri), new vscode.Range(location.range.start.line, location.range.start.character, location.range.end.line, location.range.end.character))), 'peek', 'No super implementation found'); })); - context.subscriptions.push(commands.registerCommand('java.rename.element.at', async (offset) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.rename.element.at', async (offset) => { const editor = window.activeTextEditor; if (editor) { await commands.executeCommand('editor.action.rename', [ @@ -522,7 +523,7 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { ]); } })); - context.subscriptions.push(commands.registerCommand('java.surround.with', async (items) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.surround.with', async (items) => { const selected: any = await window.showQuickPick(items, { placeHolder: 'Surround with ...' }); if (selected) { if (selected.userData.edit && selected.userData.edit.changes) { @@ -539,12 +540,12 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { await commands.executeCommand(selected.userData.command.command, ...(selected.userData.command.arguments || [])); } })); - context.subscriptions.push(commands.registerCommand('db.add.all.connection', async () => { + context.subscriptions.push(commands.registerCommand('nbls.db.add.all.connection', async () => { const ADD_JDBC = 'Add Database Connection'; const ADD_ADB = 'Add Oracle Autonomous DB'; const selected: any = await window.showQuickPick([ADD_JDBC, ADD_ADB], { placeHolder: 'Select type...' }); if (selected == ADD_JDBC) { - await commands.executeCommand('db.add.connection'); + await commands.executeCommand('nbls.db.add.connection'); } else if (selected == ADD_ADB) { await commands.executeCommand('nbls:Tools:org.netbeans.modules.cloud.oracle.actions.AddADBAction'); } @@ -602,32 +603,32 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { }) : ret; } }; - context.subscriptions.push(commands.registerCommand('java.run.test', async (uri, methodName?, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.run.test', async (uri, methodName?, launchConfiguration?) => { await runDebug(true, true, uri, methodName, launchConfiguration); })); - context.subscriptions.push(commands.registerCommand('java.debug.test', async (uri, methodName?, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.debug.test', async (uri, methodName?, launchConfiguration?) => { await runDebug(false, true, uri, methodName, launchConfiguration); })); - context.subscriptions.push(commands.registerCommand('java.run.single', async (uri, methodName?, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.run.single', async (uri, methodName?, launchConfiguration?) => { await runDebug(true, false, uri, methodName, launchConfiguration); })); - context.subscriptions.push(commands.registerCommand('java.debug.single', async (uri, methodName?, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.debug.single', async (uri, methodName?, launchConfiguration?) => { await runDebug(false, false, uri, methodName, launchConfiguration); })); - context.subscriptions.push(commands.registerCommand('java.project.run', async (node, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.project.run', async (node, launchConfiguration?) => { return runDebug(true, false, contextUri(node)?.toString() || '', undefined, launchConfiguration, true); })); - context.subscriptions.push(commands.registerCommand('java.project.debug', async (node, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.project.debug', async (node, launchConfiguration?) => { return runDebug(false, false, contextUri(node)?.toString() || '', undefined, launchConfiguration, true); })); - context.subscriptions.push(commands.registerCommand('java.project.test', async (node, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.project.test', async (node, launchConfiguration?) => { return runDebug(true, true, contextUri(node)?.toString() || '', undefined, launchConfiguration, true); })); - context.subscriptions.push(commands.registerCommand('java.package.test', async (uri, launchConfiguration?) => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.package.test', async (uri, launchConfiguration?) => { await runDebug(true, true, uri, undefined, launchConfiguration); })); - context.subscriptions.push(commands.registerCommand('java.open.stacktrace', async (uri, methodName, fileName, line) => { - const location: string | undefined = uri ? await commands.executeCommand('java.resolve.stacktrace.location', uri, methodName, fileName) : undefined; + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.open.stacktrace', async (uri, methodName, fileName, line) => { + const location: string | undefined = uri ? await commands.executeCommand(COMMAND_PREFIX + '.resolve.stacktrace.location', uri, methodName, fileName) : undefined; if (location) { const lNum = line - 1; window.showTextDocument(vscode.Uri.parse(location), { selection: new vscode.Range(new vscode.Position(lNum, 0), new vscode.Position(lNum, 0)) }); @@ -642,14 +643,14 @@ export function activate(context: ExtensionContext): VSNetBeansAPI { const c = await client; return (await c.sendRequest("workspace/symbol", { "query": query })) ?? []; })); - context.subscriptions.push(commands.registerCommand('java.complete.abstract.methods', async () => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.java.complete.abstract.methods', async () => { const active = vscode.window.activeTextEditor; if (active) { const position = new vscode.Position(active.selection.start.line, active.selection.start.character); - await commands.executeCommand('java.implement.all.abstract.methods', active.document.uri.toString(), position); + await commands.executeCommand(COMMAND_PREFIX + '.java.implement.all.abstract.methods', active.document.uri.toString(), position); } })); - context.subscriptions.push(commands.registerCommand('nbls.startup.condition', async () => { + context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.startup.condition', async () => { return client; })); context.subscriptions.push(commands.registerCommand('nbls.addEventListener', (eventName, listener) => { @@ -1143,7 +1144,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex constructor(provider : CustomizableTreeDataProvider, client : NbLanguageClient) { this.provider = provider; - this.setCommand = vscode.commands.registerCommand('java.local.db.set.preferred.connection', (n) => this.setPreferred(n)); + this.setCommand = vscode.commands.registerCommand(COMMAND_PREFIX + '.local.db.set.preferred.connection', (n) => this.setPreferred(n)); } decorateChildren(element: Visualizer, children: Visualizer[]): Visualizer[] { @@ -1157,7 +1158,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex if (!(item.contextValue && item.contextValue.match(/class:org.netbeans.api.db.explorer.DatabaseConnection/))) { return item; } - return vscode.commands.executeCommand('java.db.preferred.connection').then((id) => { + return vscode.commands.executeCommand(COMMAND_PREFIX + '.db.preferred.connection').then((id) => { if (id == vis.id) { item.description = '(default)'; } @@ -1167,7 +1168,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex setPreferred(...args : any[]) { const id : number = args[0]?.id || -1; - vscode.commands.executeCommand('nbls:Database:netbeans.db.explorer.action.makepreferred', ...args); + vscode.commands.executeCommand(COMMAND_PREFIX + ':Database:netbeans.db.explorer.action.makepreferred', ...args); // refresh all this.provider.fireItemChange(); } @@ -1213,7 +1214,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex revealActiveEditor(ed); } })); - ctx.subscriptions.push(vscode.commands.registerCommand("java.select.editor.projects", () => revealActiveEditor())); + ctx.subscriptions.push(vscode.commands.registerCommand(COMMAND_PREFIX + ".select.editor.projects", () => revealActiveEditor())); // attempt to reveal NOW: if (netbeansConfig.get("revealActiveInProjects")) { @@ -1253,7 +1254,7 @@ function doActivateWithJDK(specifiedJDK: string | null, context: ExtensionContex view.dispose(); break; case 'command': - vscode.commands.executeCommand('nb.htmlui.process.command', message.data); + vscode.commands.executeCommand(COMMAND_PREFIX + '.htmlui.process.command', message.data); break; } }); @@ -1427,7 +1428,7 @@ class NetBeansConfigurationInitialProvider implements vscode.DebugConfigurationP u = vscode.window.activeTextEditor?.document?.uri } let result : vscode.DebugConfiguration[] = []; - const configNames : string[] | null | undefined = await vscode.commands.executeCommand('java.project.configurations', u?.toString()); + const configNames : string[] | null | undefined = await vscode.commands.executeCommand(COMMAND_PREFIX + '.project.configurations', u?.toString()); if (configNames) { let first : boolean = true; for (let cn of configNames) { @@ -1472,7 +1473,7 @@ class NetBeansConfigurationDynamicProvider implements vscode.DebugConfigurationP return []; } let result : vscode.DebugConfiguration[] = []; - const attachConnectors : DebugConnector[] | null | undefined = await vscode.commands.executeCommand('java.attachDebugger.configurations'); + const attachConnectors : DebugConnector[] | null | undefined = await vscode.commands.executeCommand(COMMAND_PREFIX + '.java.attachDebugger.configurations'); if (attachConnectors) { for (let ac of attachConnectors) { const debugConfig : vscode.DebugConfiguration = { @@ -1484,7 +1485,7 @@ class NetBeansConfigurationDynamicProvider implements vscode.DebugConfigurationP let defaultValue: string = ac.defaultValues[i]; if (!defaultValue.startsWith("${command:")) { // Create a command that asks for the argument value: - let cmd: string = "java.attachDebugger.connector." + ac.id + "." + ac.arguments[i]; + let cmd: string = COMMAND_PREFIX + ".java.attachDebugger.connector." + ac.id + "." + ac.arguments[i]; debugConfig[ac.arguments[i]] = "${command:" + cmd + "}"; if (!commandValues.has(cmd)) { commandValues.set(cmd, ac.defaultValues[i]); diff --git a/java/java.lsp.server/vscode/src/launchConfigurations.ts b/java/java.lsp.server/vscode/src/launchConfigurations.ts index f5f13ee9c705..ef53dc4fbf89 100644 --- a/java/java.lsp.server/vscode/src/launchConfigurations.ts +++ b/java/java.lsp.server/vscode/src/launchConfigurations.ts @@ -22,6 +22,7 @@ import { commands, CompletionItem, CompletionList, ExtensionContext, languages, import { InsertTextFormat } from 'vscode-languageclient'; import * as jsoncp from 'jsonc-parser'; import * as fs from 'fs'; +import { COMMAND_PREFIX } from "./extension"; export function updateLaunchConfig() { workspace.findFiles('.vscode/launch.json').then(async files => { @@ -83,7 +84,7 @@ export function registerCompletion(context: ExtensionContext) { let completionItems: ProviderResult> | CompletionItem[]; if (path.length == 1) { // Get all configurations: - completionItems = commands.executeCommand('java.project.configuration.completion', uri); + completionItems = commands.executeCommand(COMMAND_PREFIX + '.project.configuration.completion', uri); } else { let node: jsoncp.Node = currentNode; if (currentNode.type == 'property' && currentNode.parent) { @@ -94,11 +95,11 @@ export function registerCompletion(context: ExtensionContext) { node = currentNode.parent; let attributesMap = getAttributes(node); // Get possible values of property 'propName': - completionItems = commands.executeCommand('java.project.configuration.completion', uri, attributesMap, propName); + completionItems = commands.executeCommand(COMMAND_PREFIX + '.project.configuration.completion', uri, attributesMap, propName); } else { let attributesMap = getAttributes(node); // Get additional possible attributes: - completionItems = commands.executeCommand('java.project.configuration.completion', uri, attributesMap); + completionItems = commands.executeCommand(COMMAND_PREFIX + '.project.configuration.completion', uri, attributesMap); } } return (completionItems as Thenable>).then(itemsList => { diff --git a/java/java.lsp.server/vscode/src/test/suite/extension.test.ts b/java/java.lsp.server/vscode/src/test/suite/extension.test.ts index 01aec1c16e64..d398e2d2dd41 100644 --- a/java/java.lsp.server/vscode/src/test/suite/extension.test.ts +++ b/java/java.lsp.server/vscode/src/test/suite/extension.test.ts @@ -94,7 +94,7 @@ suite('Extension Test Suite', () => { try { console.log("Test: invoking compile"); - let res = await vscode.commands.executeCommand("nbls.workspace.compile"); + let res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".workspace.compile"); console.log(`Test: compile finished with ${res}`); } catch (error) { dumpJava(); @@ -184,7 +184,7 @@ suite('Extension Test Suite', () => { try { console.log("Test: get project java source roots"); - let res: any = await vscode.commands.executeCommand("java.get.project.source.roots", Uri.file(folder).toString()); + let res: any = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.source.roots", Uri.file(folder).toString()); console.log(`Test: get project java source roots finished with ${res}`); assert.ok(res, "No java source root returned"); assert.strictEqual(res.length, 2, `Invalid number of java roots returned`); @@ -192,21 +192,21 @@ suite('Extension Test Suite', () => { assert.strictEqual(res[1], path.join('file:', folder, 'src', 'test', 'java') + path.sep, `Invalid java test source root returned`); console.log("Test: get project resource roots"); - res = await vscode.commands.executeCommand("java.get.project.source.roots", Uri.file(folder).toString(), 'resources'); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.source.roots", Uri.file(folder).toString(), 'resources'); console.log(`Test: get project resource roots finished with ${res}`); assert.ok(res, "No resource root returned"); assert.strictEqual(res.length, 1, `Invalid number of resource roots returned`); assert.strictEqual(res[0], path.join('file:', folder, 'src', 'main', 'resources') + path.sep, `Invalid resource root returned`); console.log("Test: get project compile classpath"); - res = await vscode.commands.executeCommand("java.get.project.classpath", Uri.file(folder).toString()); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.classpath", Uri.file(folder).toString()); console.log(`Test: get project compile classpath finished with ${res}`); assert.ok(res, "No compile classpath returned"); assert.strictEqual(res.length, 9, `Invalid number of compile classpath roots returned`); assert.ok(res.find((item: any) => item === path.join('file:', folder, 'target', 'classes') + path.sep, `Invalid compile classpath root returned`)); console.log("Test: get project source classpath"); - res = await vscode.commands.executeCommand("java.get.project.classpath", Uri.file(folder).toString(), 'SOURCE'); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.classpath", Uri.file(folder).toString(), 'SOURCE'); console.log(`Test: get project source classpath finished with ${res}`); assert.ok(res, "No source classpath returned"); assert.strictEqual(res.length, 3, `Invalid number of source classpath roots returned`); @@ -215,25 +215,25 @@ suite('Extension Test Suite', () => { assert.ok(res.find((item: any) => item === path.join('file:', folder, 'src', 'test', 'java') + path.sep, `Invalid source classpath root returned`)); console.log("Test: get project boot classpath"); - res = await vscode.commands.executeCommand("java.get.project.classpath", Uri.file(folder).toString(), 'BOOT'); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.classpath", Uri.file(folder).toString(), 'BOOT'); console.log(`Test: get project boot classpath finished with ${res}`); assert.ok(res, "No boot classpath returned"); assert.ok(res.length > 0, `Invalid number of boot classpath roots returned`); console.log("Test: get project boot source classpath"); - res = await vscode.commands.executeCommand("java.get.project.classpath", Uri.file(folder).toString(), 'BOOT', true); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.classpath", Uri.file(folder).toString(), 'BOOT', true); console.log(`Test: get project boot source classpath finished with ${res}`); assert.ok(res, "No boot source classpath returned"); assert.ok(res.length > 0, `Invalid number of boot source classpath roots returned`); console.log("Test: get all project packages"); - res = await vscode.commands.executeCommand("java.get.project.packages", Uri.file(folder).toString()); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.packages", Uri.file(folder).toString()); console.log(`Test: get all project packages finished with ${res}`); assert.ok(res, "No packages returned"); assert.ok(res.length > 0, `Invalid number of packages returned`); console.log("Test: get project source packages"); - res = await vscode.commands.executeCommand("java.get.project.packages", Uri.file(folder).toString(), true); + res = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.packages", Uri.file(folder).toString(), true); console.log(`Test: get project source packages finished with ${res}`); assert.ok(res, "No packages returned"); assert.strictEqual(res.length, 1, `Invalid number of packages returned`); @@ -253,7 +253,7 @@ suite('Extension Test Suite', () => { vscode.workspace.saveAll(); try { console.log("Test: load workspace tests"); - let tests: any = await vscode.commands.executeCommand("java.load.workspace.tests", Uri.file(folder).toString()); + let tests: any = await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".load.workspace.tests", Uri.file(folder).toString()); console.log(`Test: load workspace tests finished with ${tests}`); assert.ok(tests, "No tests returned for workspace"); assert.strictEqual(tests.length, 2, `Invalid number of test suites returned`); @@ -266,7 +266,7 @@ suite('Extension Test Suite', () => { console.log("Test: run all workspace tests"); const workspaceFolder = (vscode.workspace.workspaceFolders!)[0]; - await vscode.commands.executeCommand('java.run.test', workspaceFolder.uri.toString()); + await vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + '.run.test', workspaceFolder.uri.toString()); console.log(`Test: run all workspace tests finished`); } catch (error) { dumpJava(); diff --git a/java/java.lsp.server/vscode/src/test/suite/testutils.ts b/java/java.lsp.server/vscode/src/test/suite/testutils.ts index dfc015e52984..5abc8776254b 100644 --- a/java/java.lsp.server/vscode/src/test/suite/testutils.ts +++ b/java/java.lsp.server/vscode/src/test/suite/testutils.ts @@ -125,7 +125,7 @@ export function waitCommandsReady() : Promise { function checkCommands(attempts : number, cb : () => void) { try { // this command is parameterless - vscode.commands.executeCommand("java.attachDebugger.configurations") + vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.attachDebugger.configurations") console.log("NBLS commands ready."); resolve(); } catch (e) { @@ -159,9 +159,9 @@ async function waitProjectRecognized(someJavaFile : string) { return waitCommandsReady().then(() => { const u : vscode.Uri = vscode.Uri.file(someJavaFile); // clear out possible bad or negative caches. - return vscode.commands.executeCommand("java.clear.project.caches").then( + return vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".clear.project.caches").then( // this should assure opening the root with the created project. - () => vscode.commands.executeCommand("java.get.project.packages", u.toString()) + () => vscode.commands.executeCommand(myExtension.COMMAND_PREFIX + ".java.get.project.packages", u.toString()) ); }); } diff --git a/java/java.lsp.server/vscode/src/testAdapter.ts b/java/java.lsp.server/vscode/src/testAdapter.ts index 2141996ccc41..fb5563e94021 100644 --- a/java/java.lsp.server/vscode/src/testAdapter.ts +++ b/java/java.lsp.server/vscode/src/testAdapter.ts @@ -21,6 +21,7 @@ import { commands, debug, tests, workspace, CancellationToken, TestController, TestItem, TestRunProfileKind, TestRunRequest, Uri, TestRun, TestMessage, Location, Position, MarkdownString } from "vscode"; import * as path from 'path'; import { asRange, TestCase, TestSuite } from "./protocol"; +import { COMMAND_PREFIX } from "./extension"; export class NbTestAdapter { @@ -41,7 +42,7 @@ export class NbTestAdapter { async load(): Promise { for (let workspaceFolder of workspace.workspaceFolders || []) { - const loadedTests: any = await commands.executeCommand('java.load.workspace.tests', workspaceFolder.uri.toString()); + const loadedTests: any = await commands.executeCommand(COMMAND_PREFIX + '.load.workspace.tests', workspaceFolder.uri.toString()); if (loadedTests) { loadedTests.forEach((suite: TestSuite) => { this.updateTests(suite); @@ -64,7 +65,7 @@ export class NbTestAdapter { this.set(item, 'enqueued'); const idx = item.id.indexOf(':'); if (!cancellation.isCancellationRequested) { - await commands.executeCommand(request.profile?.kind === TestRunProfileKind.Debug ? 'java.debug.single' : 'java.run.single', item.uri.toString(), idx < 0 ? undefined : item.id.slice(idx + 1)); + await commands.executeCommand(request.profile?.kind === TestRunProfileKind.Debug ? COMMAND_PREFIX + '.debug.single' : COMMAND_PREFIX + '.run.single', item.uri.toString(), idx < 0 ? undefined : item.id.slice(idx + 1)); } } } @@ -72,7 +73,7 @@ export class NbTestAdapter { this.testController.items.forEach(item => this.set(item, 'enqueued')); for (let workspaceFolder of workspace.workspaceFolders || []) { if (!cancellation.isCancellationRequested) { - await commands.executeCommand(request.profile?.kind === TestRunProfileKind.Debug ? 'java.debug.test': 'java.run.test', workspaceFolder.uri.toString()); + await commands.executeCommand(request.profile?.kind === TestRunProfileKind.Debug ? COMMAND_PREFIX + '.debug.test': COMMAND_PREFIX + '.run.test', workspaceFolder.uri.toString()); } } } @@ -308,7 +309,7 @@ export class NbTestAdapter { } const result = regExp.exec(line); if (result) { - message.appendText(result[1]).appendText('(').appendMarkdown(`[${result[3]}](command:java.open.stacktrace?${encodeURIComponent(JSON.stringify([currentTestUri, result[2], result[4], +result[5]]))})`).appendText(')'); + message.appendText(result[1]).appendText('(').appendMarkdown(`[${result[3]}](command:${COMMAND_PREFIX}.open.stacktrace?${encodeURIComponent(JSON.stringify([currentTestUri, result[2], result[4], +result[5]]))})`).appendText(')'); } else { message.appendText(line); } diff --git a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/CodeLensProviderImpl.java b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/CodeLensProviderImpl.java index 4d9db1f37512..0c6b3507c1bc 100644 --- a/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/CodeLensProviderImpl.java +++ b/java/java.openjdk.project/src/org/netbeans/modules/java/openjdk/jtreg/CodeLensProviderImpl.java @@ -65,8 +65,8 @@ private List doComputeCodeLens(Document doc) { Tag testTag = testTags.get(0); Range lenSpan = new Range(testTag.getTagStart(), testTag.getTagEnd()); List params = Collections.singletonList(file.toURI().toString()); - return Collections.unmodifiableList(Arrays.asList(new CodeLens(lenSpan, new Command(Bundle.DN_RunTest(), "java.run.test", params), null), - new CodeLens(lenSpan, new Command(Bundle.DN_DebugTest(), "java.debug.test", params), null))); + return Collections.unmodifiableList(Arrays.asList(new CodeLens(lenSpan, new Command(Bundle.DN_RunTest(), "nbls.run.test", params), null), + new CodeLens(lenSpan, new Command(Bundle.DN_DebugTest(), "nbls.debug.test", params), null))); } } From aa5755a61c8eb7bfc773a664ef4ddb14a1513b58 Mon Sep 17 00:00:00 2001 From: Laszlo Kishalmi Date: Thu, 19 Oct 2023 11:18:15 +0200 Subject: [PATCH 02/11] Fix Gradle version change in wrapper.properties --- .../gradle/execute/GradleDistributionProviderImpl.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/extide/gradle/src/org/netbeans/modules/gradle/execute/GradleDistributionProviderImpl.java b/extide/gradle/src/org/netbeans/modules/gradle/execute/GradleDistributionProviderImpl.java index be671794de28..2b0104009340 100644 --- a/extide/gradle/src/org/netbeans/modules/gradle/execute/GradleDistributionProviderImpl.java +++ b/extide/gradle/src/org/netbeans/modules/gradle/execute/GradleDistributionProviderImpl.java @@ -74,7 +74,6 @@ public class GradleDistributionProviderImpl implements GradleDistributionProvide final NbGradleProjectImpl project; private GradleDistribution dist; private final PropertyChangeListener pcl; - private URI distributionURI; public GradleDistributionProviderImpl(Project project) { this.project = (NbGradleProjectImpl) project; @@ -83,8 +82,7 @@ public GradleDistributionProviderImpl(Project project) { URI uri = (URI) evt.getNewValue(); if ((uri != null) && (uri.getPath() != null) && uri.getPath().endsWith(GradleFiles.WRAPPER_PROPERTIES)) { URI newDistURI = getWrapperDistributionURI(); - if (GradleSettings.getDefault().isWrapperPreferred() && (distributionURI != null) && !Objects.equal(distributionURI, newDistURI)) { - distributionURI = newDistURI; + if (GradleSettings.getDefault().isWrapperPreferred() && (dist != null) && !Objects.equal(dist.getDistributionURI(), newDistURI)) { distributionChanged(); } } From e75a76521f57590ffd87931563510991151a0790 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Thu, 19 Oct 2023 13:19:21 +0200 Subject: [PATCH 03/11] JDK Downloader: fix current GA/EA values use better caching to avoid per-call latency overhead --- .../netbeans/modules/java/disco/Client.java | 70 ++++++++++--------- .../java/disco/SelectPackagePanel.java | 6 +- 2 files changed, 41 insertions(+), 35 deletions(-) diff --git a/java/java.disco/src/org/netbeans/modules/java/disco/Client.java b/java/java.disco/src/org/netbeans/modules/java/disco/Client.java index e6f027d66f0a..539627f69c9a 100644 --- a/java/java.disco/src/org/netbeans/modules/java/disco/Client.java +++ b/java/java.disco/src/org/netbeans/modules/java/disco/Client.java @@ -38,13 +38,13 @@ import io.foojay.api.discoclient.pkg.Pkg; import io.foojay.api.discoclient.pkg.Scope; import io.foojay.api.discoclient.util.PkgInfo; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.Future; import java.util.stream.Collectors; - -import static java.util.Arrays.asList; +import java.util.stream.Stream; public class Client { @@ -54,6 +54,8 @@ public class Client { private List majorVersions; private List distributions; + private Client() {} + public static Client getInstance() { return INSTANCE; } @@ -65,35 +67,51 @@ private synchronized DiscoClient getDisco() { return client; } - private Client() { + public synchronized List getAllMajorVersions() { + if (majorVersions == null) { + majorVersions = Collections.unmodifiableList(new ArrayList<>(getDisco().getAllMajorVersions(true))); + } + return majorVersions; + } + + public synchronized List getDistributions() { + if (distributions == null) { + distributions = Collections.unmodifiableList( + getDisco().getDistributions().stream() + .filter(distribution -> distribution.getScopes().contains(Scope.BUILD_OF_OPEN_JDK)) + .filter(distribution -> distribution.getScopes().contains(Scope.PUBLIC)) + .collect(Collectors.toList()) + ); + } + return distributions; } /** * Returns all major versions which are still maintained (excludes EA releases). */ - public synchronized final List getAllMaintainedMajorVersions() { - if (majorVersions == null) { - majorVersions = getDisco().getAllMajorVersions( - Optional.of(true), // maintained - Optional.of(false), // EA - Optional.of(true), // GA - Optional.of(false)); // build - } - return majorVersions; + public Stream getAllMaintainedMajorVersions() { + return getAllMajorVersions().stream() + .filter(v -> v.isEarlyAccessOnly() != null && !v.isEarlyAccessOnly()) + .filter(MajorVersion::isMaintained); } - public synchronized MajorVersion getLatestLts(boolean includeEA) { - return getDisco().getLatestLts(includeEA); + public MajorVersion getLatestGAVersion() { + return getAllMaintainedMajorVersions() + .findFirst() + .orElse(new MajorVersion(21)); } - public synchronized MajorVersion getLatestSts(boolean includeEA) { - return getDisco().getLatestSts(includeEA); + public MajorVersion getLatestEAVersion() { + return getAllMajorVersions().stream() + .filter(v -> v.isEarlyAccessOnly() != null && v.isEarlyAccessOnly()) + .findFirst() + .orElse(new MajorVersion(21)); } public synchronized List getPkgs(final Distribution distribution, final VersionNumber versionNumber, final Latest latest, final OperatingSystem operatingSystem, final Architecture architecture, final ArchiveType archiveType, final PackageType packageType, final boolean ea, final boolean javafxBundled) { - return getDisco().getPkgs(asList(distribution), + return getDisco().getPkgs(List.of(distribution), versionNumber, latest, operatingSystem, @@ -104,26 +122,14 @@ public synchronized List getPkgs(final Distribution distribution, final Ver packageType, javafxBundled, /*directlyDownloadable*/ true, - ea ? asList(ReleaseStatus.GA, ReleaseStatus.EA) : asList(ReleaseStatus.GA), + ea ? List.of(ReleaseStatus.GA, ReleaseStatus.EA) : List.of(ReleaseStatus.GA), TermOfSupport.NONE, - asList(Scope.PUBLIC), + List.of(Scope.PUBLIC), null ); } - public synchronized List getDistributions() { - if (distributions == null) { - distributions = Collections.unmodifiableList(getDisco().getDistributions() - .stream() - .filter(distribution -> distribution.getScopes().contains(Scope.BUILD_OF_OPEN_JDK)) - .filter(distribution -> distribution.getScopes().contains(Scope.PUBLIC)) - .collect(Collectors.toList()) - ); - } - return distributions; - } - - public synchronized Optional getDistribution(String text) { + public Optional getDistribution(String text) { return getDistributions().stream() .filter(d -> d.getSynonyms().contains(text)) .findFirst(); diff --git a/java/java.disco/src/org/netbeans/modules/java/disco/SelectPackagePanel.java b/java/java.disco/src/org/netbeans/modules/java/disco/SelectPackagePanel.java index e0083d38ce65..8d861e541128 100644 --- a/java/java.disco/src/org/netbeans/modules/java/disco/SelectPackagePanel.java +++ b/java/java.disco/src/org/netbeans/modules/java/disco/SelectPackagePanel.java @@ -128,11 +128,11 @@ public Result(List versionNumbers, Map versionN //loading stuff when ui shown submit(() -> { int minVersion = 6; - int maxVersion = discoClient.getLatestSts(true).getAsInt(); - int current = discoClient.getLatestSts(false).getAsInt(); + int maxVersion = discoClient.getLatestEAVersion().getAsInt(); + int current = discoClient.getLatestGAVersion().getAsInt(); // limit to LTS + current - Map maintainedVersions = discoClient.getAllMaintainedMajorVersions().stream() + Map maintainedVersions = discoClient.getAllMaintainedMajorVersions() .filter(v -> v.getAsInt() >= minVersion && v.getAsInt() <= current) // defensive filter, the API returned an EA JDK as released .filter(v -> v.getAsInt() == current || v.getTermOfSupport() == TermOfSupport.LTS) .collect(Collectors.toMap(MajorVersion::getAsInt, MajorVersion::getTermOfSupport)); From 23df8c64bfaa513b1aff7465f080ec655befd91f Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Thu, 19 Oct 2023 18:53:37 +0200 Subject: [PATCH 04/11] Fix unnamed main method detection code. Code gave wrong results when other methods were nearby. --- .../netbeans/api/java/source/SourceUtils.java | 20 +++++++++---------- .../api/java/source/SourceUtilsTest.java | 11 ++++++++++ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java b/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java index c01c35ff0280..390a9b19a8f3 100644 --- a/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java +++ b/java/java.source.base/src/org/netbeans/api/java/source/SourceUtils.java @@ -1048,7 +1048,12 @@ public static boolean isMainMethod (final ExecutableElement method) { int highestPriority = Integer.MAX_VALUE; for (ExecutableElement sibling : ElementFilter.methodsIn(method.getEnclosingElement().getEnclosedElements())) { - highestPriority = Math.min(highestPriority, mainMethodPriority(sibling)); + if (mainCandidate(sibling)) { + highestPriority = Math.min(highestPriority, mainMethodPriority(sibling)); + if (highestPriority < currentMethodPriority) { + break; + } + } } return currentMethodPriority == highestPriority; @@ -1085,22 +1090,15 @@ private static boolean mainCandidate(ExecutableElement method) { return true; } + // 0 is highest private static int mainMethodPriority(ExecutableElement method) { long flags = ((Symbol.MethodSymbol)method).flags(); boolean isStatic = (flags & Flags.STATIC) != 0; boolean hasParams = !method.getParameters().isEmpty(); if (isStatic) { - if (hasParams) { - return 0; - } else { - return 1; - } + return hasParams ? 0 : 1; } else { - if (hasParams) { - return 2; - } else { - return 3; - } + return hasParams ? 2 : 3; } } diff --git a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTest.java b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTest.java index d5812c729843..198cd6a77388 100644 --- a/java/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTest.java +++ b/java/java.source.base/test/unit/src/org/netbeans/api/java/source/SourceUtilsTest.java @@ -84,6 +84,7 @@ public SourceUtilsTest(String testName) { super(testName); } + @Override protected void setUp() throws Exception { clearWorkDir(); SourceUtilsTestUtil.prepareTest( @@ -539,6 +540,16 @@ public TestCase(String code, String mainMethod) { " void main() {}\n" + "}\n", "Test:main:([Ljava/lang/String;)V"), + new TestCase("public class Test {\n" + + " public static void plain(String... args) {}\n" + + " void main() {}\n" + + "}\n", + "Test:main:()V"), + new TestCase("public class Test {\n" + + " void main() {}\n" + + " public static void plain(String... args) {}\n" + + "}\n", + "Test:main:()V"), }; File work = getWorkDir(); FileObject workFO = FileUtil.toFileObject(work); From c9c2ebf309ad8ce7ada39bc46f41090e0abadae6 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Thu, 19 Oct 2023 19:52:57 +0200 Subject: [PATCH 05/11] Fix Git show history regression. It appears RevWalk can create 24 flags, LogCommand could create 25 and the history view would fail. This tries to maintain the limit of 24. It is not clear why this worked in past, since the limit was there before too. --- .../src/org/netbeans/libs/git/jgit/commands/LogCommand.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/LogCommand.java b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/LogCommand.java index cb9460b80dad..f3432c04e21d 100644 --- a/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/LogCommand.java +++ b/ide/libs.git/src/org/netbeans/libs/git/jgit/commands/LogCommand.java @@ -210,8 +210,8 @@ private void markBranchFlags (Map allBranches, RevWalk walk, } } else { usedFlags.add(flagId); - if (i < 25) { - i = i + 1; + if (i <= 23) { // leave one spare flag for the run method, see RevWalk.newFlag() + i++; RevFlag flag = walk.newFlag(flagId); List branches = new ArrayList<>(allBranches.size()); branches.add(e.getValue()); @@ -253,7 +253,7 @@ protected String getCommandDescription () { } public GitRevisionInfo[] getRevisions () { - return revisions.toArray(new GitRevisionInfo[revisions.size()]); + return revisions.toArray(new GitRevisionInfo[0]); } private void addRevision (GitRevisionInfo info) { From 49fac41e034dd4a163907b1830dfba5af0ac722d Mon Sep 17 00:00:00 2001 From: Laszlo Kishalmi Date: Fri, 20 Oct 2023 14:40:48 +0200 Subject: [PATCH 06/11] Try to close Gradle Daemons on exit. --- .../gradle/GradleConnectorManager.java | 80 +++++++++++++++++++ .../gradle/GradleProjectConnection.java | 6 +- .../modules/gradle/loaders/GradleDaemon.java | 40 ---------- .../spi/newproject/TemplateOperation.java | 2 + .../gradle/api/GradleBaseProjectTest.java | 1 + 5 files changed, 87 insertions(+), 42 deletions(-) create mode 100644 extide/gradle/src/org/netbeans/modules/gradle/GradleConnectorManager.java diff --git a/extide/gradle/src/org/netbeans/modules/gradle/GradleConnectorManager.java b/extide/gradle/src/org/netbeans/modules/gradle/GradleConnectorManager.java new file mode 100644 index 000000000000..eb7c91501b44 --- /dev/null +++ b/extide/gradle/src/org/netbeans/modules/gradle/GradleConnectorManager.java @@ -0,0 +1,80 @@ +/* + * 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.gradle; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.logging.Logger; +import org.gradle.tooling.GradleConnector; +import org.netbeans.api.project.Project; +import org.openide.modules.OnStop; + +/** + * + * @author lkishalmi + */ +public final class GradleConnectorManager { + + private final Map projectConnector = new WeakHashMap<>(); + private final List connectors = new ArrayList<>(); + + private static final GradleConnectorManager INSTANCE = new GradleConnectorManager(); + private static final Logger LOG = Logger.getLogger(GradleConnectorManager.class.getName()); + + private GradleConnectorManager() {} + + public static GradleConnectorManager getDefault() { + return INSTANCE; + } + + public GradleConnector getConnector(Project prj) { + synchronized (connectors) { + GradleConnector ret = projectConnector.computeIfAbsent(prj, p -> { + GradleConnector conn = GradleConnector.newConnector(); + connectors.add(conn); + return conn; + }); + return ret; + } + } + + + public void disconnectAll() { + LOG.info("Disconnecting from Gradle Daemons."); //NOI18N + synchronized (connectors) { + projectConnector.clear(); + + connectors.forEach(GradleConnector::disconnect); + connectors.clear(); + } + LOG.info("Disconnecting from Gradle Daemons. Done."); //NOI18N + } + + @OnStop + public static class DisconnectGradle implements Runnable { + + @Override + public void run() { + GradleConnectorManager.getDefault().disconnectAll(); + } + + } +} diff --git a/extide/gradle/src/org/netbeans/modules/gradle/GradleProjectConnection.java b/extide/gradle/src/org/netbeans/modules/gradle/GradleProjectConnection.java index d74535dcd98b..a8160bfd0660 100644 --- a/extide/gradle/src/org/netbeans/modules/gradle/GradleProjectConnection.java +++ b/extide/gradle/src/org/netbeans/modules/gradle/GradleProjectConnection.java @@ -37,6 +37,8 @@ import org.gradle.tooling.ResultHandler; import org.gradle.tooling.TestLauncher; import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.ProjectUtils; import org.netbeans.modules.gradle.api.NbGradleProject; import org.netbeans.modules.gradle.api.execute.GradleDistributionManager; import org.netbeans.modules.gradle.api.execute.GradleDistributionManager.GradleDistribution; @@ -151,8 +153,8 @@ private > T setJavaHome(T launcher) { return launcher; } - private static ProjectConnection createConnection(GradleDistribution dist, File projectDir) { - GradleConnector gconn = GradleConnector.newConnector(); + private ProjectConnection createConnection(GradleDistribution dist, File projectDir) { + GradleConnector gconn = GradleConnectorManager.getDefault().getConnector(project); gconn = gconn.useGradleUserHomeDir(dist.getGradleUserHome()); if (dist.isAvailable()) { gconn = gconn.useInstallation(dist.getDistributionDir()); diff --git a/extide/gradle/src/org/netbeans/modules/gradle/loaders/GradleDaemon.java b/extide/gradle/src/org/netbeans/modules/gradle/loaders/GradleDaemon.java index a068117a5b3a..2d87172c1b60 100644 --- a/extide/gradle/src/org/netbeans/modules/gradle/loaders/GradleDaemon.java +++ b/extide/gradle/src/org/netbeans/modules/gradle/loaders/GradleDaemon.java @@ -20,7 +20,6 @@ package org.netbeans.modules.gradle.loaders; import org.netbeans.modules.gradle.api.NbGradleProject; -import org.netbeans.modules.gradle.api.execute.GradleCommandLine; import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -31,12 +30,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import org.gradle.tooling.BuildAction; -import org.gradle.tooling.BuildActionExecuter; -import org.gradle.tooling.BuildController; -import org.gradle.tooling.GradleConnectionException; -import org.gradle.tooling.GradleConnector; -import org.gradle.tooling.ProjectConnection; import org.openide.modules.InstalledFileLocator; import org.openide.modules.Places; import org.openide.util.RequestProcessor; @@ -55,11 +48,6 @@ public final class GradleDaemon { private static final String PROP_TOOLING_JAR = "NETBEANS_TOOLING_JAR"; private static final String TOOLING_JAR = InstalledFileLocator.getDefault().locate(TOOLING_JAR_NAME, NbGradleProject.CODENAME_BASE, false).getAbsolutePath().replace("\\", "\\\\"); - private static final String DAEMON_LOADED = "Daemon Loaded."; //NOI18N - private static final String LOADER_PROJECT_NAME = "modules/gradle/daemon-loader"; //NOI18N - private static final File LOADER_PROJECT_DIR = InstalledFileLocator.getDefault().locate(LOADER_PROJECT_NAME, NbGradleProject.CODENAME_BASE, false); - private static final DummyBuildAction DUMMY_ACTION = new DummyBuildAction(); - private static final Logger LOG = Logger.getLogger(GradleDaemon.class.getName()); private GradleDaemon() {} @@ -82,32 +70,4 @@ public static String initScript() { } return initScript.getAbsolutePath(); } - - private static void doLoadDaemon() { - GradleConnector gconn = GradleConnector.newConnector(); - ProjectConnection pconn = gconn.forProjectDirectory(LOADER_PROJECT_DIR).connect(); - BuildActionExecuter action = pconn.action(DUMMY_ACTION); - GradleCommandLine cmd = new GradleCommandLine(); - cmd.setFlag(GradleCommandLine.Flag.OFFLINE, true); - cmd.addParameter(GradleCommandLine.Parameter.INIT_SCRIPT, initScript()); - cmd.configure(action); - try { - action.run(); - } catch (GradleConnectionException | IllegalStateException ex) { - // Well for some reason we were not able to load Gradle. - // Ignoring that for now - } finally { - pconn.close(); - } - } - - private static class DummyBuildAction implements BuildAction { - - @Override - public String execute(BuildController bc) { - return DAEMON_LOADED; - } - - } - } diff --git a/extide/gradle/src/org/netbeans/modules/gradle/spi/newproject/TemplateOperation.java b/extide/gradle/src/org/netbeans/modules/gradle/spi/newproject/TemplateOperation.java index b8afbfbb417c..f065d391bfe3 100644 --- a/extide/gradle/src/org/netbeans/modules/gradle/spi/newproject/TemplateOperation.java +++ b/extide/gradle/src/org/netbeans/modules/gradle/spi/newproject/TemplateOperation.java @@ -318,6 +318,7 @@ public Set execute() { // Well for some reason we were not able to load Gradle. // Ignoring that for now } + gconn.disconnect(); return Collections.singleton(FileUtil.toFileObject(target)); } } @@ -492,6 +493,7 @@ public Set execute() { // Well for some reason we were not able to load Gradle. // Ignoring that for now } + gconn.disconnect(); return null; } diff --git a/extide/gradle/test/unit/src/org/netbeans/modules/gradle/api/GradleBaseProjectTest.java b/extide/gradle/test/unit/src/org/netbeans/modules/gradle/api/GradleBaseProjectTest.java index e8b2313fd8ad..546178028efc 100644 --- a/extide/gradle/test/unit/src/org/netbeans/modules/gradle/api/GradleBaseProjectTest.java +++ b/extide/gradle/test/unit/src/org/netbeans/modules/gradle/api/GradleBaseProjectTest.java @@ -245,6 +245,7 @@ private Project makeProjectWithWrapper(String subdir, String gradleVersion) thro OpenProjects.getDefault().openProjects().get(); NbGradleProject.get(p).toQuality("Load data", NbGradleProject.Quality.FULL, false).toCompletableFuture().get(); + gconn.disconnect(); return p; } From a0e9284b89a25cd4c6616b0bc1a04d021ad054d0 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 21 Oct 2023 18:46:28 +0200 Subject: [PATCH 07/11] Update FlatLaf from 3.2.1 to 3.2.5 Changes: https://github.com/JFormDesigner/FlatLaf/releases/tag/3.2.5 and: https://github.com/JFormDesigner/FlatLaf/releases/tag/3.2.4 and: https://github.com/JFormDesigner/FlatLaf/releases/tag/3.2.3 and: https://github.com/JFormDesigner/FlatLaf/releases/tag/3.2.2 --- platform/libs.flatlaf/external/binaries-list | 2 +- ...laf-3.2.1-license.txt => flatlaf-3.2.5-license.txt} | 4 ++-- platform/libs.flatlaf/manifest.mf | 2 +- platform/libs.flatlaf/nbproject/project.properties | 10 +++++----- platform/libs.flatlaf/nbproject/project.xml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) rename platform/libs.flatlaf/external/{flatlaf-3.2.1-license.txt => flatlaf-3.2.5-license.txt} (99%) diff --git a/platform/libs.flatlaf/external/binaries-list b/platform/libs.flatlaf/external/binaries-list index bacfaefd8b41..411b5bb2268a 100644 --- a/platform/libs.flatlaf/external/binaries-list +++ b/platform/libs.flatlaf/external/binaries-list @@ -15,4 +15,4 @@ # specific language governing permissions and limitations # under the License. -90F4BD7E9208C38CC065E84555A423E871AADE18 com.formdev:flatlaf:3.2.1 +A180D2525801750F8BE57A1FAE71181593C9BB36 com.formdev:flatlaf:3.2.5 diff --git a/platform/libs.flatlaf/external/flatlaf-3.2.1-license.txt b/platform/libs.flatlaf/external/flatlaf-3.2.5-license.txt similarity index 99% rename from platform/libs.flatlaf/external/flatlaf-3.2.1-license.txt rename to platform/libs.flatlaf/external/flatlaf-3.2.5-license.txt index 8a458fe3aeed..c0f6c1b61912 100644 --- a/platform/libs.flatlaf/external/flatlaf-3.2.1-license.txt +++ b/platform/libs.flatlaf/external/flatlaf-3.2.5-license.txt @@ -1,7 +1,7 @@ Name: FlatLaf Look and Feel Description: FlatLaf Look and Feel -Version: 3.2.1 -Files: flatlaf-3.2.1.jar +Version: 3.2.5 +Files: flatlaf-3.2.5.jar License: Apache-2.0 Origin: FormDev Software GmbH. URL: https://www.formdev.com/flatlaf/ diff --git a/platform/libs.flatlaf/manifest.mf b/platform/libs.flatlaf/manifest.mf index fe134e13d68b..2d9a5a3a43e0 100644 --- a/platform/libs.flatlaf/manifest.mf +++ b/platform/libs.flatlaf/manifest.mf @@ -4,4 +4,4 @@ OpenIDE-Module: org.netbeans.libs.flatlaf/1 OpenIDE-Module-Install: org/netbeans/libs/flatlaf/Installer.class OpenIDE-Module-Specification-Version: 1.16 AutoUpdate-Show-In-Client: false -OpenIDE-Module-Implementation-Version: 3.2.1 +OpenIDE-Module-Implementation-Version: 3.2.5 diff --git a/platform/libs.flatlaf/nbproject/project.properties b/platform/libs.flatlaf/nbproject/project.properties index d46167d79658..178d70e7f2ee 100644 --- a/platform/libs.flatlaf/nbproject/project.properties +++ b/platform/libs.flatlaf/nbproject/project.properties @@ -31,12 +31,12 @@ spec.version.base.fatal.warning=false # # So when FlatLaf is updated, the OpenIDE-Module-Implementation-Version entry # in manifest.mf needs to be updated to match the new FlatLaf version. -release.external/flatlaf-3.2.1.jar=modules/ext/flatlaf-3.2.1.jar +release.external/flatlaf-3.2.5.jar=modules/ext/flatlaf-3.2.5.jar -release.external/flatlaf-3.2.1.jar!/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll=modules/lib/flatlaf-windows-x86.dll -release.external/flatlaf-3.2.1.jar!/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll=modules/lib/flatlaf-windows-x86_64.dll -release.external/flatlaf-3.2.1.jar!/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll=modules/lib/flatlaf-windows-arm64.dll -release.external/flatlaf-3.2.1.jar!/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so=modules/lib/libflatlaf-linux-x86_64.so +release.external/flatlaf-3.2.5.jar!/com/formdev/flatlaf/natives/flatlaf-windows-x86.dll=modules/lib/flatlaf-windows-x86.dll +release.external/flatlaf-3.2.5.jar!/com/formdev/flatlaf/natives/flatlaf-windows-x86_64.dll=modules/lib/flatlaf-windows-x86_64.dll +release.external/flatlaf-3.2.5.jar!/com/formdev/flatlaf/natives/flatlaf-windows-arm64.dll=modules/lib/flatlaf-windows-arm64.dll +release.external/flatlaf-3.2.5.jar!/com/formdev/flatlaf/natives/libflatlaf-linux-x86_64.so=modules/lib/libflatlaf-linux-x86_64.so jnlp.verify.excludes=\ modules/lib/flatlaf-windows-x86.dll,\ modules/lib/flatlaf-windows-x86_64.dll,\ diff --git a/platform/libs.flatlaf/nbproject/project.xml b/platform/libs.flatlaf/nbproject/project.xml index 064af2f799cc..b3550440f9f3 100644 --- a/platform/libs.flatlaf/nbproject/project.xml +++ b/platform/libs.flatlaf/nbproject/project.xml @@ -48,8 +48,8 @@ com.formdev.flatlaf.util - ext/flatlaf-3.2.1.jar - external/flatlaf-3.2.1.jar + ext/flatlaf-3.2.5.jar + external/flatlaf-3.2.5.jar From 409740b82f24d8c243ac4550023d7bb25611f7b1 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Mon, 2 Oct 2023 20:52:16 +0200 Subject: [PATCH 08/11] Priming build and reload improvements. --- .github/workflows/main.yml | 2 +- .../nbcode/integration/maven.properties | 1 + java/maven/apichanges.xml | 14 + java/maven/build.xml | 3 +- java/maven/nbproject/project.properties | 2 +- .../modules/maven/NbArtifactFixer.java | 49 ++ .../modules/maven/NbMavenProjectImpl.java | 182 +++++- .../modules/maven/api/NbMavenProject.java | 54 +- .../AbstractProjectClassPathImpl.java | 9 + .../classpath/ClassPathProviderImpl.java | 2 + .../maven/classpath/CompileClassPathImpl.java | 7 +- .../maven/customizer/BasicInfoPanel.java | 4 + .../execute/MavenCommandLineExecutor.java | 15 +- .../modules/maven/execute/ReactorChecker.java | 12 +- .../maven/modelcache/MavenProjectCache.java | 223 ++++--- .../maven/nodes/AddDependencyPanel.java | 3 + .../problems/MavenModelProblemsProvider.java | 11 +- .../maven/problems/ProblemReporterImpl.java | 2 +- .../maven/problems/SanityBuildAction.java | 17 +- .../spi/newproject/CreateProjectBuilder.java | 2 +- .../projects/multiproject/democa/.gitignore | 15 + .../data/projects/multiproject/democa/LICENSE | 201 ++++++ .../projects/multiproject/democa/lib/pom.xml | 198 ++++++ .../projects/multiproject/democa/oci/pom.xml | 253 ++++++++ .../data/projects/multiproject/democa/pom.xml | 50 ++ .../maven/NbMavenProjectImpl2Test.java | 597 ++++++++++++++++++ .../modules/maven/NbMavenProjectImplTest.java | 3 + .../maven/execute/MavenExecMonitor.java | 50 ++ .../modules/maven/execute/MockMavenExec.java | 23 +- .../maven/problems/PrimingActionTest.java | 14 +- .../actions/ProvidedConfigurationsTest.java | 7 +- 31 files changed, 1883 insertions(+), 142 deletions(-) create mode 100644 java/maven/test/unit/data/projects/multiproject/democa/.gitignore create mode 100644 java/maven/test/unit/data/projects/multiproject/democa/LICENSE create mode 100644 java/maven/test/unit/data/projects/multiproject/democa/lib/pom.xml create mode 100644 java/maven/test/unit/data/projects/multiproject/democa/oci/pom.xml create mode 100644 java/maven/test/unit/data/projects/multiproject/democa/pom.xml create mode 100644 java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImpl2Test.java create mode 100644 java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecMonitor.java diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 13521bf848dd..321a2450faf5 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -758,7 +758,7 @@ jobs: timeout-minutes: 60 strategy: matrix: - java: [ '11' ] + java: [ '11', '17' ] steps: - name: Set up JDK ${{ matrix.java }} diff --git a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties index aca469984308..22eaeaae63d3 100644 --- a/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties +++ b/java/java.lsp.server/nbcode/integration/src/org/netbeans/modules/nbcode/integration/maven.properties @@ -17,3 +17,4 @@ primingBuild.snapshot.goals=install primingBuild.regular.goals=install +skipTests=true diff --git a/java/maven/apichanges.xml b/java/maven/apichanges.xml index 8854fb3799e7..eb9cc37425b9 100644 --- a/java/maven/apichanges.xml +++ b/java/maven/apichanges.xml @@ -83,6 +83,20 @@ is the proper place. + + + Support for partially loaded projects + + + + + + Added a + getPratialProject that returns potentially incompletely loaded project instead of a mocked-up fallback (see isErrorPlaceholder(). + Also added a isIncomplete() check that checks project's status. + + + diff --git a/java/maven/build.xml b/java/maven/build.xml index 6bd5eb7fd1a7..1cfa92a1a7d3 100644 --- a/java/maven/build.xml +++ b/java/maven/build.xml @@ -99,7 +99,8 @@ - + + diff --git a/java/maven/nbproject/project.properties b/java/maven/nbproject/project.properties index 871f4bacb8d7..f20d64491d08 100644 --- a/java/maven/nbproject/project.properties +++ b/java/maven/nbproject/project.properties @@ -22,7 +22,7 @@ javadoc.apichanges=${basedir}/apichanges.xml javadoc.arch=${basedir}/arch.xml javahelp.hs=maven.hs extra.module.files=maven-nblib/ -spec.version.base=2.160.0 +spec.version.base=2.161.0 # The CPExtender test fails in library processing (not randomly) since NetBeans 8.2; disabling. test.excludes=**/CPExtenderTest.class diff --git a/java/maven/src/org/netbeans/modules/maven/NbArtifactFixer.java b/java/maven/src/org/netbeans/modules/maven/NbArtifactFixer.java index e44c2ffc5812..0d8e7ae2cff7 100644 --- a/java/maven/src/org/netbeans/modules/maven/NbArtifactFixer.java +++ b/java/maven/src/org/netbeans/modules/maven/NbArtifactFixer.java @@ -27,6 +27,7 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.maven.artifact.DefaultArtifact; @@ -105,6 +106,10 @@ public class NbArtifactFixer implements ArtifactFixer { //instead of workarounds down the road, we set the artifact's file here. // some stacktraces to maven/aether do set it after querying our code, but some don't for reasons unknown to me. artifact.setFile(f); + Set s = CAPTURE_FAKE_ARTIFACTS.get(); + if (s != null) { + s.add(artifact); + } return f; } catch (IOException x) { Exceptions.printStackTrace(x); @@ -149,4 +154,48 @@ private static synchronized File createFallbackPOM(String groupId, String artifa return fallbackPOM; } + public interface ExceptionCallable { + public T call() throws E; + } + + @SuppressWarnings("unchecked") + private static void sneakyThrow(Throwable exception) throws T { + throw (T) exception; + } + + /** + * Collects faked artifacts, which would be otherwise hidden in maven infrastructure. The value is only valid during {@link #collectFallbackArtifacts}, which + * can be invoked recursively. + */ + private static ThreadLocal> CAPTURE_FAKE_ARTIFACTS = new ThreadLocal>(); + + /** + * Performs an operation and collects forged artifacts created during that operation. The invocation can be nested; each invocation gets only artifacts from its own 'level', + * not those from possible nested invocations. The function passes on all runtime exceptions and checked exception thrown by the operation. + * + * @param value produced by the executed operation + * @param exception thrown from the operation + * @param code the operation to call and monitor + * @param collector callback that will get collected artifacts. + * @return + * @throws E + */ + public static T collectFallbackArtifacts(ExceptionCallable code, Consumer> collector) throws E { + Set save = CAPTURE_FAKE_ARTIFACTS.get(); + try { + CAPTURE_FAKE_ARTIFACTS.set(new HashSet<>()); + return code.call(); + } catch (Error | RuntimeException r) { + throw r; + } catch (Exception ex) { + sneakyThrow(ex); + // unreachable + throw new Error(); + } finally { + if (collector != null) { + collector.accept(CAPTURE_FAKE_ARTIFACTS.get()); + } + CAPTURE_FAKE_ARTIFACTS.set(save); + } + } } diff --git a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java index d8a0bedca2d3..4fa076bc0c37 100644 --- a/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java +++ b/java/maven/src/org/netbeans/modules/maven/NbMavenProjectImpl.java @@ -41,7 +41,6 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Properties; import java.util.Set; import java.util.WeakHashMap; @@ -56,7 +55,6 @@ import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; import org.apache.maven.cli.MavenCli; import org.apache.maven.execution.MavenExecutionRequest; -import org.apache.maven.execution.MavenExecutionResult; import org.apache.maven.model.Model; import org.apache.maven.model.Resource; import org.apache.maven.model.building.ModelBuildingException; @@ -109,6 +107,7 @@ import org.openide.util.Lookup; import org.openide.util.NbBundle.Messages; import org.openide.util.NbCollections; +import org.openide.util.Pair; import org.openide.util.RequestProcessor; import org.openide.util.Utilities; import org.openide.util.WeakListeners; @@ -134,6 +133,14 @@ public final class NbMavenProjectImpl implements Project { private final RequestProcessor.Task reloadTask = RELOAD_RP.create(new Runnable() { @Override public void run() { + if (LOG.isLoggable(Level.FINE)) { + MavenProject x; + synchronized (NbMavenProjectImpl.this) { + x = project == null ? null : project.get(); + } + LOG.log(Level.FINE, "Project {0} starting reload. Currentproject is: {1}", + new Object[] { System.identityHashCode(x == null ? this : x ), x }); + } problemReporter.clearReports(); //#167741 -this will trigger node refresh? MavenProject prj = loadOriginalMavenProject(true); MavenProject old; @@ -303,6 +310,15 @@ public String getHintJavaPlatform() { */ //TODO revisit usage, eventually should be only reuse MavenProjectCache public @NonNull MavenProject loadMavenProject(MavenEmbedder embedder, List activeProfiles, Properties properties) { + ProjectActionContext.Builder b = ProjectActionContext.newBuilder(this). + withProfiles(activeProfiles); + for (String pn : properties.stringPropertyNames()) { + b.withProperty(pn, properties.getProperty(pn)); + } + + return MavenProjectCache.loadMavenProject(projectFile, + b.context(), null); + /* try { MavenExecutionRequest req = embedder.createMavenExecutionRequest(); req.addActiveProfiles(activeProfiles); @@ -340,6 +356,7 @@ public String getHintJavaPlatform() { LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + getProjectDirectory(), exc); //NOI18N } return MavenProjectCache.getFallbackProject(this.getPOMFile()); + */ } /** @@ -374,7 +391,8 @@ public MavenProject loadParentOf(MavenEmbedder embedder, MavenProject project) t request.setRepositorySession(maven.newRepositorySession(req)); if (project.getParentFile() != null) { - parent = builder.build(project.getParentFile(), request).getProject(); + req.setPom(project.getParentFile()); + parent = MavenProjectCache.loadOriginalMavenProjectInternal(embedder, req); } else if (project.getModel().getParent() != null) { parent = builder.build(project.getParentArtifact(), request).getProject(); } @@ -408,6 +426,21 @@ public Map createSystemPropsForPropertyExpres public Map createUserPropsForPropertyExpressions() { return NbCollections.checkedMapByCopy(configProvider.getActiveConfiguration().getProperties(), String.class, String.class, true); } + + /** + * Returns the current parsed project state. May return {@code null}, if the project was never loaded or expired from the cache, but + * never blocks on Maven infrastructure and is very fast. + * @return current project or {@code null} + */ + @CheckForNull + public MavenProject getOriginalMavenProjectOrNull() { + synchronized (this) { + if (project == null) { + return null; + } + return project.get(); + } + } /** * getter for the maven's own project representation.. this instance is cached but gets reloaded @@ -435,7 +468,8 @@ public Map createUserPropsForPropertyExpress } /** - * Returns the original project, or waits for reload task if already pending. + * Returns the original project, or waits for reload task if already pending. Use with care, as + * the method blocks until the project reload eventually finishes in the reload thread / RP. * @return possibly reloaded Maven project. */ public MavenProject getFreshOriginalMavenProject() { @@ -544,12 +578,6 @@ void stopHardReferencingMavenPoject() { model = null; } newproject = MavenProjectCache.getMavenProject(this.getPOMFile(), reload); - if (newproject == null) { //null when no pom.xml in project folder.. - newproject = MavenProjectCache.getFallbackProject(projectFile); - LOG.log(Level.FINE, "Project {0} going to fallback, with packaging: {1}", new Object[] { getPOMFile(), newproject.getPackaging() }); - } - final MavenExecutionResult res = MavenProjectCache.getExecutionResult(newproject); - final MavenProject np = newproject; } finally { if (LOG.isLoggable(Level.FINE) && SwingUtilities.isEventDispatchThread()) { LOG.log(Level.FINE, "Project " + getProjectDirectory().getPath() + " loaded in AWT event dispatching thread!", new RuntimeException()); @@ -559,29 +587,141 @@ void stopHardReferencingMavenPoject() { return newproject; } - - + /** + * Task that potential project reloads should wait on. If set, a {@link fireProjectReload}(true) will be scheduled only after this blocker finishes. + */ + // @GuardedBy(this) + private List blockingList = new ArrayList<>(); + + /** + * Task, that will be returned if the reload is blocked. Needed as an existing available reload task instance is finished before it is scheduled again. + */ + // @GuardedBy(this) + private RequestProcessor.Task reloadCompletionTask; + + // tests only ! + synchronized Pair, RequestProcessor.Task> reloadBlockingState() { + return Pair.of(new ArrayList<>(this.blockingList), this.reloadCompletionTask); + } + + // tests only ! + RequestProcessor.Task getReloadTask() { + return reloadTask; + } + + /** + * Schedules project operation that delays potential reloads. If a reload is posted, it will be performed only after + * this operation compeltes (successfully, or erroneously). Multiple project operations can be scheduled, an eventual project reload + * should happen after all those operations complete. It is possible to postpone project reload indefinitely, avoid unnecessary + * operation schedules. + *

+ * To avoid race condition on task startup, this method actually creates and schedules the task so it blocks reloads from its inception. + * It returns the value of the worker task as the result value. + * wrapper. + * @param rp request processor that should schedule the task + * @param delay optional delay, use 0 for immediate run + * @param r operation to run + * @return the scheduled task + */ + public RequestProcessor.Task scheduleProjectOperation(RequestProcessor rp, Runnable r, int delay) { + RequestProcessor.Task t = rp.create(r); + if (Boolean.getBoolean("test.reload.sync")) { + LOG.log(Level.FINE, "Running the blocking task synchronously (test.reload.sync set)"); + t.run(); + return t; + } else { + synchronized (this) { + blockingList.add(t); + if (LOG.isLoggable(Level.FINER)) { + LOG.log(Level.FINER, "Blocking project reload on task {0}, blocking queue: {1}", new Object[] { t, blockingList }); + } + t.addTaskListener((e) -> { + synchronized (this) { + blockingList.remove(t); + if (!blockingList.isEmpty()) { + LOG.log(Level.FINER, "Project {0} task {1} finished, still blocked", new Object[] { this, t }); + return; + } + if (reloadCompletionTask == null) { + LOG.log(Level.FINER, "Project {0} task {1} finished, no reload requested", new Object[] { this, t }); + return; + } + } + LOG.log(Level.FINER, "Project {0} task {1} finished, project reload released", new Object[] { this, t }); + fireProjectReload(true); + }); + } + t.schedule(delay); + return t; + } + } + public RequestProcessor.Task fireProjectReload() { + return fireProjectReload(false); + } + + /** + * Schedules project reload. If `waitForBlockers` is true and {@link #scheduleProjectOperation} registered some task(s), project reload + * will be postponed until after those task(s) finish. The returned task completes after the project reload itself completes (after the potential + * delays). + *

+ * As a result of project's reload, child projects may be reloaded, but the returned task does not wait for children reload to complete. + * + * @param waitForBlockers + * @return the task that completes after project reloads. + */ + public RequestProcessor.Task fireProjectReload(boolean waitForBlockers) { //#227101 not only AWT and project read/write mutex has to be checked, there are some additional more //complex scenarios that can lead to deadlock. Just give up and always fire changes in separate RP. if (Boolean.getBoolean("test.reload.sync")) { reloadTask.run(); //for tests just do sync reload, even though silly, even sillier is to attempt to sync the threads.. } else { - reloadTask.schedule(0); //asuming here that schedule(0) will move the scheduled task in the queue if not yet executed + synchronized (this) { + if (blockingList.isEmpty()) { + RequestProcessor.Task fin; + + fin = this.reloadCompletionTask; + reloadCompletionTask = null; + LOG.log(Level.FINER, "Project {0} reload scheduled, no blockers", this ); + reloadTask.schedule(0); + if (fin != null) { + reloadTask.addTaskListener((e) -> { + fin.run(); + }); + } + } else if (waitForBlockers) { + LOG.log(Level.FINER, "Project {0} reload blocked, blockers: {1}", new Object[] { this, blockingList }); + if (reloadCompletionTask == null) { + reloadCompletionTask = RELOAD_RP.create(() -> {}); + } + return reloadCompletionTask; + } else { + // potentially reload will happen again, after all blocking tasks will complete. + LOG.log(Level.FINER, "Project {0} reload forced, blockers: {1}, completion task: {2}", new Object[] { this, blockingList, reloadCompletionTask }); + reloadTask.schedule(0); + } + } } return reloadTask; } private void reloadPossibleBrokenModules(MavenProject preceding, MavenProject p) { + LOG.log(Level.FINE, "Recovery for project {2}, preceding: {0}, current: {1}, ", + new Object[] { preceding == null ? -1 : System.identityHashCode(preceding), System.identityHashCode(p), p }); // restrict to just poms that were marked as broken/incomplete. - if (!(MavenProjectCache.isFallbackproject(preceding) || + if (!(MavenProjectCache.isIncompleteProject(preceding) || // the project is tagged by Boolean.TRUE, if a SanityBuildAction was created for it. preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") == Boolean.TRUE)) { + LOG.log(Level.FINER, "Project is not fallbach: {0}, {1}", new Object[] { + MavenProjectCache.isIncompleteProject(preceding), + preceding.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") + }); return; } // but do not cascade from projects, which are themselves broken. if (MavenProjectCache.isFallbackproject(p)) { + LOG.log(Level.FINE, "New project is still fallback, skipping"); return; } File basePOMFile = p.getFile().getParentFile(); @@ -593,10 +733,15 @@ private void reloadPossibleBrokenModules(MavenProject preceding, MavenProject p) } MavenProject child = MavenProjectCache.getMavenProject(modPom, true, false); if (child == null) { + LOG.log(Level.FINE, "Child project {0} is not cached yet", modPom); continue; } + LOG.log(Level.FINE, "Child project fallback status: {0}, {1}", new Object[] { + MavenProjectCache.isIncompleteProject(child), + child.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") + }); // the project may have more problems, more subtle, but now repair just total breakage - if (!MavenProjectCache.isFallbackproject(child) && child.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") != Boolean.TRUE) { + if (!MavenProjectCache.isIncompleteProject(child) && child.getContextValue("org.netbeans.modules.maven.problems.primingNotDone") != Boolean.TRUE) { LOG.log(Level.FINE, "Project for module {0} is not a fallback, skipping", modName); continue; } @@ -612,7 +757,7 @@ private void reloadPossibleBrokenModules(MavenProject preceding, MavenProject p) } else { LOG.log(Level.INFO, "Recovering module {0}, pomfile {1}", new Object[] { modName, modPom }); NbMavenProjectImpl childImpl = c.getLookup().lookup(NbMavenProjectImpl.class); - childImpl.fireProjectReload(); + childImpl.fireProjectReload(true); } } catch (IOException ex) { LOG.log(Level.FINE, "Error getting module project {0} is not a project", modName); @@ -1259,7 +1404,10 @@ protected List getParents() { while(true) { try { MavenProject parent = loadParentOf(getEmbedder(), project); - File parentFile = parent != null ? parent.getFile() : null; + if (parent == null || NbMavenProject.isErrorPlaceholder(parent)) { + break; + } + File parentFile = parent.getFile(); if(parentFile != null) { ret.add(parentFile); project = parent; diff --git a/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java b/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java index e1575a269dd3..c8c3e86b87c7 100644 --- a/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java +++ b/java/maven/src/org/netbeans/modules/maven/api/NbMavenProject.java @@ -194,9 +194,9 @@ private NbMavenProject(NbMavenProjectImpl proj) { } /** - * - * @return - * @since + * Checks if the project is completely broken. Also see {@link #getPartialProject}. + * @return true, if the project is broken and could not be loaded + * @see #getPartialProject */ public boolean isUnloadable() { return MavenProjectCache.isFallbackproject(getMavenProject()); @@ -586,10 +586,12 @@ private void fireChange(URI uri) { * */ private RequestProcessor.Task fireProjectReload() { - return project.fireProjectReload(); + return project.fireProjectReload(true); } private void doFireReload() { + MavenProject p = project.getOriginalMavenProjectOrNull(); + LOG.log(Level.FINE, "Firing PROJECT change for maven project {0}, mavenprj {1}", new Object[] { this, System.identityHashCode(p == null ? this : p) }); FileUtil.refreshFor(FileUtil.toFile(project.getProjectDirectory())); NbMavenProjectImpl.refreshLocalRepository(project); support.firePropertyChange(PROP_PROJECT, null, null); @@ -630,16 +632,58 @@ public static void removePropertyChangeListener(Project prj, PropertyChangeListe assert false : "Attempted to remove PropertyChangeListener from project " + prj; //NOI18N } } + + /** + * Retrieves at least partial project information. A MavenProject instance may be a fallback in case the reading + * fails because of locally missing artifacts and/or referenced parents. However partial model may be available. The function + * returns the passed project, if it read correctly. Otherwise, it attempts to locate a partially load project and returns that one. + * If a partial project is not available, it will return the passed (fallback) project. + *

+ * The result can be checked to be {@link #isErrorPlaceholder} to determine if the result was a returned partial project or not. + * Note that partial projects may not resolve all references properly, be prepared for unresolved artifacts and/or plugins. Do not pass + * partial projects blindly around. + *

+ * Returns {@code null} if the passed project is {@code null} + * @param project the project to check + * @return partial project if the passed project did not load properly and the partial project is available. + * @since 2.161 + */ + public static MavenProject getPartialProject(MavenProject project) { + if (project == null) { + return null; + } + if (isIncomplete(project)) { + MavenProject pp = MavenProjectCache.getPartialProject(project); + if (pp != null) { + return pp; + } + } + return project; + } /** - * Checks whether a given project is just an error placeholder. + * Checks whether a given project is just an error placeholder. Such project may be fundamentally broken, i.e. missing + * declarations from the parent, unresolved dependencies or versions. Also see {@link #isIncomplete} * @param project a project loaded by e.g. {@link #getMavenProject} * @return true if it was loaded as an error fallback, false for a normal project * @since 2.24 + * @see #isIncomplete + * @see #getPartialProject */ public static boolean isErrorPlaceholder(@NonNull MavenProject project) { return MavenProjectCache.isFallbackproject(project); // see NbMavenProjectImpl.getFallbackProject } + + /** + * Checks if the project resolved using incomplete or missing information. Each {@link #isErrorPlaceholder} is an incomplete project. + * If the project is just missing proper referenced artifacts, it will not be reported as a {@link #isErrorPlaceholder}, but as {@link #isIncomplete}. + * @param project + * @return true, if the project is not completely resolved + * @since 2.161 + */ + public static boolean isIncomplete(@NonNull MavenProject project) { + return MavenProjectCache.isIncompleteProject(project); + } @Override public String toString() { return project.toString(); diff --git a/java/maven/src/org/netbeans/modules/maven/classpath/AbstractProjectClassPathImpl.java b/java/maven/src/org/netbeans/modules/maven/classpath/AbstractProjectClassPathImpl.java index ba919d114150..b2dd0c66c27a 100644 --- a/java/maven/src/org/netbeans/modules/maven/classpath/AbstractProjectClassPathImpl.java +++ b/java/maven/src/org/netbeans/modules/maven/classpath/AbstractProjectClassPathImpl.java @@ -32,6 +32,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.apache.maven.artifact.Artifact; +import org.apache.maven.project.MavenProject; import org.netbeans.modules.maven.NbMavenProjectImpl; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.spi.java.classpath.ClassPathImplementation; @@ -54,13 +55,18 @@ public abstract class AbstractProjectClassPathImpl implements ClassPathImplement protected AbstractProjectClassPathImpl(NbMavenProjectImpl proj) { project = proj; + LOGGER.log(Level.FINER, "Creating {0} for project {1}, with original {2}", new Object[] { getClass(), proj, proj.getOriginalMavenProjectOrNull() }); //TODO make weak or remove the listeners as well?? NbMavenProject.addPropertyChangeListener(proj, new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { //explicitly listing both RESOURCE and PROJECT properties, it's unclear if both are required but since some other places call addWatchedPath but don't listen it's likely required if (NbMavenProject.PROP_RESOURCE.equals(evt.getPropertyName()) || NbMavenProject.PROP_PROJECT.equals(evt.getPropertyName())) { + MavenProject mp = project.getOriginalMavenProjectOrNull(); + LOGGER.log(Level.FINE, "{0} got change {1} from project: {2} with maven project {3}", new Object[] { getClass(), evt.getPropertyName(), project, + System.identityHashCode(mp == null ? this : null) }); if (project.getProjectWatcher().isUnloadable()) { + LOGGER.log(Level.FINER, "{0} is not loadable, exiting", project); return; //let's just continue with the old value, stripping classpath for broken project and re-creating it later serves no greater good. } List newValues = getPath(); @@ -69,6 +75,9 @@ public void propertyChange(PropertyChangeEvent evt) { synchronized (AbstractProjectClassPathImpl.this) { oldvalue = resources; hasChanged = hasChanged(oldvalue, newValues); + LOGGER.log(Level.FINER, "{0}: {1} classpath is: {2}, {3} entries", new Object[] { + getClass(), project, newValues, newValues.size() + }); // System.out.println("checking=" + AbstractProjectClassPathImpl.this.getClass()); if (hasChanged) { resources = newValues; diff --git a/java/maven/src/org/netbeans/modules/maven/classpath/ClassPathProviderImpl.java b/java/maven/src/org/netbeans/modules/maven/classpath/ClassPathProviderImpl.java index 009555c25326..fda13392d1e8 100644 --- a/java/maven/src/org/netbeans/modules/maven/classpath/ClassPathProviderImpl.java +++ b/java/maven/src/org/netbeans/modules/maven/classpath/ClassPathProviderImpl.java @@ -538,6 +538,7 @@ protected boolean isReset(PropertyChangeEvent evt) { boolean reset = false; if( (NbMavenProject.PROP_RESOURCE.equals(evt.getPropertyName()) && evt.getNewValue() instanceof URI)) { File file = Utilities.toFile((URI) evt.getNewValue()); + LOGGER.log(Level.FINER, "{0} checking reset with file {1}", new Object[] { getClass(), file }); for (String sourceRoot : proj.getOriginalMavenProject().getCompileSourceRoots()) { if(file.equals(new File(sourceRoot, MODULE_INFO_JAVA))) { reset = true; @@ -701,6 +702,7 @@ public ClassPathSelector(NbMavenProjectImpl proj) { // maven checks recursively all source roots for module-info, // for performace reasons we will be checking and listening only on the root of a source root NbMavenProject.addPropertyChangeListener(proj, (evt) -> { + LOGGER.log(Level.FINER, "{0} got property change {1} from {2}", new Object[] { getClass(), evt, proj }); if (isReset(evt)) { active = null; support.firePropertyChange(PROP_ACTIVE_CLASS_PATH, null, null); diff --git a/java/maven/src/org/netbeans/modules/maven/classpath/CompileClassPathImpl.java b/java/maven/src/org/netbeans/modules/maven/classpath/CompileClassPathImpl.java index 26b789cd80ed..c748267e63a6 100644 --- a/java/maven/src/org/netbeans/modules/maven/classpath/CompileClassPathImpl.java +++ b/java/maven/src/org/netbeans/modules/maven/classpath/CompileClassPathImpl.java @@ -26,6 +26,8 @@ import java.util.EnumSet; import java.util.List; import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; import org.apache.maven.artifact.Artifact; import org.apache.maven.project.MavenProject; import org.netbeans.api.java.classpath.ClassPath; @@ -38,7 +40,7 @@ * @author Milos Kleint */ class CompileClassPathImpl extends AbstractProjectClassPathImpl implements FlaggedClassPathImplementation { - + private static final Logger LOGGER = Logger.getLogger(CompileClassPathImpl.class.getName()); private volatile boolean incomplete; private final boolean addOutputDir; @@ -52,6 +54,9 @@ public CompileClassPathImpl(NbMavenProjectImpl proj, boolean addOutputDir) { URI[] createPath() { List lst = new ArrayList<>(); boolean broken = getCompileArtifacts(getMavenProject().getOriginalMavenProject(), lst); + MavenProject mp = getMavenProject().getOriginalMavenProjectOrNull(); + LOGGER.log(Level.FINER, "{0} for project {1}: creating path for {2}: size {4} - {3}", + new Object[] { getClass(), getMavenProject(), System.identityHashCode(mp == null ? this : mp), lst, lst.size() }); if(addOutputDir) { lst.add(Utilities.toURI(getProject().getProjectWatcher().getOutputDirectory(false))); } diff --git a/java/maven/src/org/netbeans/modules/maven/customizer/BasicInfoPanel.java b/java/maven/src/org/netbeans/modules/maven/customizer/BasicInfoPanel.java index 1ae432b9eea9..abfb42514be1 100644 --- a/java/maven/src/org/netbeans/modules/maven/customizer/BasicInfoPanel.java +++ b/java/maven/src/org/netbeans/modules/maven/customizer/BasicInfoPanel.java @@ -28,6 +28,7 @@ import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuildingException; import org.netbeans.modules.maven.NbMavenProjectImpl; +import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.api.customizer.ModelHandle2; import org.netbeans.modules.maven.api.customizer.support.ReflectionTextComponentUpdater; import org.netbeans.modules.maven.api.customizer.support.TextComponentUpdater; @@ -66,6 +67,9 @@ private void initValues() { NbMavenProjectImpl nbi = prj.getLookup().lookup(NbMavenProjectImpl.class); assert nbi != null; project = nbi.loadParentOf(EmbedderFactory.getProjectEmbedder(), handle.getProject()); + if (NbMavenProject.isErrorPlaceholder(project)) { + project = null; + } } catch (ProjectBuildingException ex) { project = null; } diff --git a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java index 99e500c34c85..c26f350c5f41 100644 --- a/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java +++ b/java/maven/src/org/netbeans/modules/maven/execute/MavenCommandLineExecutor.java @@ -173,9 +173,14 @@ public static ExecutorTask executeMaven(final RunConfig config, InputOutput io, * Hooks for tests to mock the Maven execution. */ public static class ExecuteMaven { + // tests only + MavenExecutor createCommandLineExecutor(RunConfig config, InputOutput io, TabContext tc) { + return new MavenCommandLineExecutor(config, io, tc); + } + public ExecutorTask execute(RunConfig config, InputOutput io, TabContext tc) { LifecycleManager.getDefault().saveAll(); - MavenExecutor exec = new MavenCommandLineExecutor(config, io, tc); + MavenExecutor exec = createCommandLineExecutor(config, io, tc); ExecutorTask task = ExecutionEngine.getDefault().execute(config.getTaskDisplayName(), exec, new ProxyNonSelectableInputOutput(exec.getInputOutput())); exec.setTask(task); task.addTaskListener(new TaskListener() { @@ -390,6 +395,7 @@ public void actionPerformed(ActionEvent e) { if (prj != null) { NbMavenProjectImpl impl = prj.getLookup().lookup(NbMavenProjectImpl.class); if (impl != null) { + // this reload must not wait for blockers. RequestProcessor.Task reloadTask = impl.fireProjectReload(); reloadTask.waitFinished(); } @@ -516,7 +522,7 @@ private static List createMavenExecutionCommand(RunConfig config, Constr } if (config.getReactorStyle() != RunConfig.ReactorStyle.NONE) { File basedir = config.getExecutionDirectory(); - MavenProject mp = config.getMavenProject(); + MavenProject mp = NbMavenProject.getPartialProject(config.getMavenProject()); File projdir = NbMavenProject.isErrorPlaceholder(mp) ? basedir : mp.getBasedir(); String rel = basedir != null && projdir != null ? FileUtilities.relativizeFile(basedir, projdir) : null; if (!".".equals(rel)) { @@ -627,7 +633,8 @@ private static String quote2apos(String s) { return sb.toString(); } - private ProcessBuilder constructBuilder(final RunConfig clonedConfig, InputOutput ioput) { + // tests only + ProcessBuilder constructBuilder(final RunConfig clonedConfig, InputOutput ioput) { File javaHome = null; Map envMap = new LinkedHashMap(); for (Map.Entry entry : clonedConfig.getProperties().entrySet()) { @@ -1100,7 +1107,7 @@ private File getAltMavenLocation() { private File searchMavenWrapper(RunConfig config) { String fileName = Utilities.isWindows() ? "mvnw.cmd" : "mvnw"; //NOI18N - MavenProject project = config.getMavenProject(); + MavenProject project = NbMavenProject.getPartialProject(config.getMavenProject()); while (project != null) { File baseDir = project.getBasedir(); if (baseDir != null) { diff --git a/java/maven/src/org/netbeans/modules/maven/execute/ReactorChecker.java b/java/maven/src/org/netbeans/modules/maven/execute/ReactorChecker.java index 35bc3692cdf3..d23c4cdd9157 100644 --- a/java/maven/src/org/netbeans/modules/maven/execute/ReactorChecker.java +++ b/java/maven/src/org/netbeans/modules/maven/execute/ReactorChecker.java @@ -64,9 +64,6 @@ public class ReactorChecker implements PrerequisitesChecker { // Unloadable? return true; } - if (NbMavenProject.isErrorPlaceholder(mavenprj.getMavenProject())) { - return true; // broken project - } NbMavenProject reactor = findReactor(mavenprj); File reactorRoot = reactor.getMavenProject().getBasedir(); @@ -104,7 +101,7 @@ public class ReactorChecker implements PrerequisitesChecker { * @return its apparent reactor root; maybe just the same project */ public static @NonNull NbMavenProject findReactor(@NonNull NbMavenProject module) { // #197232 - MavenProject prj = module.getMavenProject(); + MavenProject prj = NbMavenProject.getPartialProject(module.getMavenProject()); List models = MavenEmbedder.getModelDescriptors(prj); File moduleDir = prj.getBasedir(); File current = moduleDir; @@ -134,8 +131,11 @@ public class ReactorChecker implements PrerequisitesChecker { } } NbMavenProject p = load(prj.getBasedir().getParentFile()); - if (p != null && listsModule(moduleDir.getParentFile(), moduleDir, p.getMavenProject().getModules())) { - return findReactor(p); + if (p != null) { + MavenProject mp = NbMavenProject.getPartialProject(p.getMavenProject()); + if (listsModule(moduleDir.getParentFile(), moduleDir, mp.getModules())) { + return findReactor(p); + } } return module; } diff --git a/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java b/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java index 6d8c521e2b0e..61a50730718e 100644 --- a/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java +++ b/java/maven/src/org/netbeans/modules/maven/modelcache/MavenProjectCache.java @@ -25,16 +25,19 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; import java.util.WeakHashMap; import java.util.function.BiConsumer; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingUtilities; import org.apache.maven.AbstractMavenLifecycleParticipant; +import org.apache.maven.artifact.Artifact; import org.apache.maven.execution.DefaultMavenExecutionResult; import org.apache.maven.execution.MavenExecutionRequest; import org.apache.maven.execution.MavenExecutionResult; @@ -45,6 +48,7 @@ import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.project.ProjectActionContext; import org.netbeans.modules.maven.M2AuxilaryConfigImpl; +import org.netbeans.modules.maven.NbArtifactFixer; import org.netbeans.modules.maven.api.NbMavenProject; import org.netbeans.modules.maven.api.execute.RunConfig; import org.netbeans.modules.maven.configurations.M2Configuration; @@ -67,7 +71,27 @@ public final class MavenProjectCache { private static final Logger LOG = Logger.getLogger(MavenProjectCache.class.getName()); private static final String CONTEXT_EXECUTION_RESULT = "NB_Execution_Result"; + + /** + * The value contains the set of artifacts, that have been faked during the reading operation. + */ + private static final String CONTEXT_FAKED_ARTIFACTS = "NB_FakedArtifacts"; + + /** + * Marks a project that observed unknown build participants. + */ private static final String CONTEXT_PARTICIPANTS = "NB_AbstractParticipant_Present"; + /** + * Marks a fallback project. The project was not fully read. Value of the context key is either a Boolean.TRUE as an indicator, or + * the partially read project, which does not resolve fully. Can be extracted with {@link #getPartialProject(org.apache.maven.project.MavenProject)}. + */ + private static final String CONTEXT_PARTIAL_PROJECT = "org.netbeans.modules.maven.partialProject"; // NOI18N + + /** + * Marks a fallback project. The project is forged and is not read from the maven infrastructure. A fallback project may have a {@link #getPartialProject(org.apache.maven.project.MavenProject) partial project} + * attached. + */ + private static final String CONTEXT_FALLBACK_PROJECT = "org.netbeans.modules.maven.fallbackProject"; // NOI18N /** * Folder with module-configurable whitelist of lifecycle participants. Currently only 'ignore' can be specified. @@ -172,8 +196,107 @@ private static boolean isLifecycleParticipatnIgnored(AbstractMavenLifecycleParti return check != null && check.getAttribute(ATTR_IGNORE_ON_LOAD) == Boolean.TRUE; } - private static @NonNull MavenProject loadOriginalMavenProject(final File pomFile, ProjectActionContext ctx, RunConfig runConf) { + public static MavenProject loadOriginalMavenProjectInternal(MavenEmbedder projectEmbedder, MavenExecutionRequest req) { + MavenProject newproject = null; + File pomFile = req.getPom(); + + MavenExecutionResult res = null; + Set fakes = new HashSet<>(); long startLoading = System.currentTimeMillis(); + + try { + res = NbArtifactFixer.collectFallbackArtifacts(() -> projectEmbedder.readProjectWithDependencies(req, true), (c) -> + c.forEach(a -> { + // artifact fixer only fakes POMs. + fakes.add(projectEmbedder.createArtifactWithClassifier(a.getGroupId(), a.getArtifactId(), a.getVersion(), "pom", a.getClassifier())); // NOI18N + } + )); + newproject = res.getProject(); + + //#204898 + if (newproject != null) { + LOG.log(Level.FINE, "Loaded project for {0}, packaging: {1}", new Object[] { pomFile, newproject.getPackaging() }); + ClassLoader projectRealm = newproject.getClassRealm(); + if (projectRealm != null) { + ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(projectRealm); + try { + //boolean execute = EnableParticipantsBuildAction.isEnabled(aux); + List lookup = projectEmbedder.getPlexus().lookupList(AbstractMavenLifecycleParticipant.class); + if (lookup.size() > 0) { //just in case.. +// if (execute) { +// LOG.info("Executing External Build Participants..."); +// MavenSession session = new MavenSession( projectEmbedder.getPlexus(), newproject.getProjectBuildingRequest().getRepositorySession(), req, res ); +// session.setCurrentProject(newproject); +// session.setProjects(Collections.singletonList(newproject)); +// projectEmbedder.setUpLegacySupport(); +// projectEmbedder.getPlexus().lookup(LegacySupport.class).setSession(session); +// +// for (AbstractMavenLifecycleParticipant part : lookup) { +// try { +// Thread.currentThread().setContextClassLoader( part.getClass().getClassLoader() ); +// part.afterSessionStart(session); +// part.afterProjectsRead(session); +// } catch (MavenExecutionException ex) { +// Exceptions.printStackTrace(ex); +// } +// } +// } else { + List parts = new ArrayList(); + for (AbstractMavenLifecycleParticipant part : lookup) { + if (isLifecycleParticipatnIgnored(part)) { + //#204898 create a whitelist of known not harmful participants that can be just ignored + continue; + } + String name = part.getClass().getName(); + parts.add(name); + } + if (parts.size() > 0) { + newproject.setContextValue(CONTEXT_PARTICIPANTS, parts); + } +// } + } + } catch (ComponentLookupException e) { + // this is just silly, lookupList should return an empty list! + } finally { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + } catch (RuntimeException exc) { + //guard against exceptions that are not processed by the embedder + //#136184 NumberFormatException + LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + pomFile, exc); //NOI18N + res = new DefaultMavenExecutionResult(); + res.addException(exc); + } finally { + if (newproject == null) { + newproject = getFallbackProject(res, pomFile); + } + //#215159 clear the project building request, it references multiple Maven Models via the RepositorySession cache + //is not used in maven itself, most likely used by m2e only.. + newproject.setProjectBuildingRequest(null); + long endLoading = System.currentTimeMillis(); + LOG.log(Level.FINE, "Loaded project in {0} msec at {1}", new Object[] {endLoading - startLoading, pomFile.getPath()}); + if (LOG.isLoggable(Level.FINE) && SwingUtilities.isEventDispatchThread()) { + LOG.log(Level.FINE, "Project " + pomFile.getPath() + " loaded in AWT event dispatching thread!", new RuntimeException()); + } + if (LOG.isLoggable(Level.FINE) && !res.getExceptions().isEmpty()) { + LOG.log(Level.FINE, "Errors encountered during loading the project:"); + for (Throwable t : res.getExceptions()) { + LOG.log(Level.FINE, "Maven reported:", t); + } + } + if (!fakes.isEmpty() && !isIncompleteProject(newproject)) { + LOG.log(Level.FINE, "Incomplete artifact encountered during loading the project: {0}", fakes); + newproject.setContextValue(CONTEXT_PARTIAL_PROJECT, Boolean.TRUE); + newproject.setContextValue(CONTEXT_FAKED_ARTIFACTS, fakes); + } + } + return newproject; + } + + private static @NonNull MavenProject loadOriginalMavenProject(final File pomFile, ProjectActionContext ctx, RunConfig runConf) { MavenEmbedder projectEmbedder = EmbedderFactory.getProjectEmbedder(); MavenProject newproject = null; //TODO have independent from M2AuxiliaryConfigImpl @@ -194,7 +317,6 @@ private static boolean isLifecycleParticipatnIgnored(AbstractMavenLifecycleParti } } - MavenExecutionResult res = null; try { List mavenConfigOpts = Collections.emptyList(); for (FileObject root = projectDir; root != null; root = root.getParent()) { @@ -277,92 +399,19 @@ private static boolean isLifecycleParticipatnIgnored(AbstractMavenLifecycleParti LOG.log(Level.FINE, "request property 'packaging': {0}", req.getSystemProperties().get("packaging")); LOG.log(Level.FINE, "embedder property 'packaging': {0}", projectEmbedder.getSystemProperties().get("packaging")); } - res = projectEmbedder.readProjectWithDependencies(req, true); - newproject = res.getProject(); - - //#204898 - if (newproject != null) { - LOG.log(Level.FINE, "Loaded project for {0}, packaging: {1}", new Object[] { pomFile, newproject.getPackaging() }); - ClassLoader projectRealm = newproject.getClassRealm(); - if (projectRealm != null) { - ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(projectRealm); - try { - //boolean execute = EnableParticipantsBuildAction.isEnabled(aux); - List lookup = projectEmbedder.getPlexus().lookupList(AbstractMavenLifecycleParticipant.class); - if (lookup.size() > 0) { //just in case.. -// if (execute) { -// LOG.info("Executing External Build Participants..."); -// MavenSession session = new MavenSession( projectEmbedder.getPlexus(), newproject.getProjectBuildingRequest().getRepositorySession(), req, res ); -// session.setCurrentProject(newproject); -// session.setProjects(Collections.singletonList(newproject)); -// projectEmbedder.setUpLegacySupport(); -// projectEmbedder.getPlexus().lookup(LegacySupport.class).setSession(session); -// -// for (AbstractMavenLifecycleParticipant part : lookup) { -// try { -// Thread.currentThread().setContextClassLoader( part.getClass().getClassLoader() ); -// part.afterSessionStart(session); -// part.afterProjectsRead(session); -// } catch (MavenExecutionException ex) { -// Exceptions.printStackTrace(ex); -// } -// } -// } else { - List parts = new ArrayList(); - for (AbstractMavenLifecycleParticipant part : lookup) { - if (isLifecycleParticipatnIgnored(part)) { - //#204898 create a whitelist of known not harmful participants that can be just ignored - continue; - } - String name = part.getClass().getName(); - parts.add(name); - } - if (parts.size() > 0) { - newproject.setContextValue(CONTEXT_PARTICIPANTS, parts); - } -// } - } - } catch (ComponentLookupException e) { - // this is just silly, lookupList should return an empty list! - } finally { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - } catch (RuntimeException | IOException exc) { + newproject = loadOriginalMavenProjectInternal(projectEmbedder, req); + } catch (IOException exc) { + MavenExecutionResult res = null; //guard against exceptions that are not processed by the embedder //#136184 NumberFormatException LOG.log(Level.INFO, "Runtime exception thrown while loading maven project at " + pomFile, exc); //NOI18N res = new DefaultMavenExecutionResult(); res.addException(exc); - } finally { - if (newproject == null) { - newproject = getFallbackProject(res, pomFile); - } - //#215159 clear the project building request, it references multiple Maven Models via the RepositorySession cache - //is not used in maven itself, most likely used by m2e only.. - newproject.setProjectBuildingRequest(null); - //TODO some exceptions in result contain various model caches as well.. - newproject.setContextValue(CONTEXT_EXECUTION_RESULT, res); - long endLoading = System.currentTimeMillis(); - LOG.log(Level.FINE, "Loaded project in {0} msec at {1}", new Object[] {endLoading - startLoading, pomFile.getPath()}); - if (LOG.isLoggable(Level.FINE) && SwingUtilities.isEventDispatchThread()) { - LOG.log(Level.FINE, "Project " + pomFile.getPath() + " loaded in AWT event dispatching thread!", new RuntimeException()); - } - if (LOG.isLoggable(Level.FINE) && !res.getExceptions().isEmpty()) { - LOG.log(Level.FINE, "Errors encountered during loading the project:"); - for (Throwable t : res.getExceptions()) { - LOG.log(Level.FINE, "Maven reported:", t); - } - } + newproject = getFallbackProject(res, pomFile); } return newproject; } - private static final String CONTEXT_PARTIAL_PROJECT = "org.netbeans.modules.maven.partialProject"; // NOI18N - private static final String CONTEXT_FALLBACK_PROJECT = "org.netbeans.modules.maven.fallbackProject"; // NOI18N - /** * Create a fallback project, but patch the incomplete project from the building result into it. * The method will eventually start to return the partial project but still flagged as a fallback - see {@link #isFallbackproject(org.apache.maven.project.MavenProject)}. @@ -377,6 +426,7 @@ public static MavenProject getFallbackProject(MavenExecutionResult result, File if (result == null) { return toReturn; } + toReturn.setContextValue(CONTEXT_EXECUTION_RESULT, result); MavenProject partial = null; for (Throwable t : result.getExceptions()) { @@ -417,11 +467,24 @@ public static MavenProject getFallbackProject(File projectFile) throws Assertion return newproject; } + public static boolean isIncompleteProject(MavenProject prj) { + return prj.getContextValue(CONTEXT_PARTIAL_PROJECT) != null; + } + public static boolean isFallbackproject(MavenProject prj) { if ("error".equals(prj.getGroupId()) && "error".equals(prj.getArtifactId()) && Bundle.LBL_Incomplete_Project_Name().equals(prj.getName())) { return true; } else { - return prj.getContextValue(CONTEXT_PARTIAL_PROJECT) == Boolean.TRUE; + return prj.getContextValue(CONTEXT_FALLBACK_PROJECT) != null; + } + } + + public static MavenProject getPartialProject(MavenProject prj) { + Object o = prj.getContextValue(CONTEXT_PARTIAL_PROJECT); + if (o instanceof MavenProject) { + return (MavenProject)o; + } else { + return null; } } diff --git a/java/maven/src/org/netbeans/modules/maven/nodes/AddDependencyPanel.java b/java/maven/src/org/netbeans/modules/maven/nodes/AddDependencyPanel.java index 3f86da7bbcef..4d7345bbab4d 100644 --- a/java/maven/src/org/netbeans/modules/maven/nodes/AddDependencyPanel.java +++ b/java/maven/src/org/netbeans/modules/maven/nodes/AddDependencyPanel.java @@ -821,6 +821,9 @@ private static List getDependenciesFromDM(MavenProject project, Proj } try { localProj = p.loadParentOf(EmbedderFactory.getProjectEmbedder(), localProj); + if (NbMavenProject.isErrorPlaceholder(localProj)) { + break; + } } catch (ProjectBuildingException x) { break; } diff --git a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java index 34cddf8c5e44..b842285ff812 100644 --- a/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java +++ b/java/maven/src/org/netbeans/modules/maven/problems/MavenModelProblemsProvider.java @@ -33,9 +33,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.maven.artifact.Artifact; @@ -86,7 +83,7 @@ }, projectType = "org-netbeans-modules-maven" ) public class MavenModelProblemsProvider implements ProjectProblemsProvider, InternalActionDelegate { - static final ScheduledExecutorService RP = new RequestProcessor(MavenModelProblemsProvider.class); + static final RequestProcessor RP = new RequestProcessor(MavenModelProblemsProvider.class); private static final Logger LOG = Logger.getLogger(MavenModelProblemsProvider.class.getName()); private final PropertyChangeSupport support = new PropertyChangeSupport(this); @@ -250,6 +247,10 @@ private Pair, Boolean> doGetProblems1(boolean sync) { prj = ((NbMavenProjectImpl)project).getFreshOriginalMavenProject(); } } + if (prj != null && !sanityBuildStatus) { + prj.setContextValue("org.netbeans.modules.maven.problems.primingNotDone", null); + LOG.log(Level.FINE, "Clearing priming status of {0}, fallback status is {1}", new Object[] { prj, NbMavenProject.isErrorPlaceholder(prj) }); + } //mark the project model as checked once and cached firePropertyChange(); return Pair.of(toRet, sanityBuildStatus); @@ -495,7 +496,7 @@ public void invokeAction(String command, Lookup context) throws IllegalArgumentE listener.finished(true); } else { LOG.log(Level.FINE, "Resolving sanity build action"); - CompletableFuture r = saba.resolve(); + CompletableFuture r = saba.resolve(context); r.whenComplete((a, e) -> { listener.finished(e == null); }); diff --git a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java index 296cf3035f86..cab78a8bf229 100644 --- a/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java +++ b/java/maven/src/org/netbeans/modules/maven/problems/ProblemReporterImpl.java @@ -93,7 +93,7 @@ public final class ProblemReporterImpl implements ProblemReporter, Comparator getPendingResult() { }) @Override public CompletableFuture resolve() { + return resolve(null); + } + + public CompletableFuture resolve(Lookup context) { CompletableFuture pr = pendingResult; if (pr != null && !pr.isDone()) { LOG.log(Level.FINE, "SanityBuild.resolve returns: {0}", pendingResult); @@ -112,8 +117,12 @@ public void run() { try { LOG.log(Level.FINE, "Configuring sanity build"); BeanRunConfig config = new BeanRunConfig(); + if (context != null) { + config.setActionContext(context); + } config.setExecutionDirectory(FileUtil.toFile(nbproject.getProjectDirectory())); NbMavenProject mavenPrj = nbproject.getLookup().lookup(NbMavenProject.class); + MavenProject loaded = NbMavenProject.getPartialProject(mavenPrj.getMavenProject()); String goals; if (mavenPrj != null && mavenPrj.getMavenProject().getVersion() != null @@ -175,7 +184,7 @@ public void run() { } pendingResult = publicResult; } - MavenModelProblemsProvider.RP.submit(toRet); + ((NbMavenProjectImpl)this.nbproject).scheduleProjectOperation(MavenModelProblemsProvider.RP, toRet, 0); return publicResult; } diff --git a/java/maven/src/org/netbeans/modules/maven/spi/newproject/CreateProjectBuilder.java b/java/maven/src/org/netbeans/modules/maven/spi/newproject/CreateProjectBuilder.java index 5e01527baeca..11b3b563d090 100644 --- a/java/maven/src/org/netbeans/modules/maven/spi/newproject/CreateProjectBuilder.java +++ b/java/maven/src/org/netbeans/modules/maven/spi/newproject/CreateProjectBuilder.java @@ -129,7 +129,7 @@ public void create() { } } } - if (parent != null && MavenProjectCache.isFallbackproject(parent)) { + if (parent != null && NbMavenProject.isErrorPlaceholder(parent)) { //#240989 - guessing that unloadable parent project could be the problem. parent = null; } diff --git a/java/maven/test/unit/data/projects/multiproject/democa/.gitignore b/java/maven/test/unit/data/projects/multiproject/democa/.gitignore new file mode 100644 index 000000000000..5a03bc30a460 --- /dev/null +++ b/java/maven/test/unit/data/projects/multiproject/democa/.gitignore @@ -0,0 +1,15 @@ +Thumbs.db +.DS_Store +.gradle +build/ +target/ +out/ +.micronaut/ +.idea +*.iml +*.ipr +*.iws +.project +.settings +.classpath +.factorypath diff --git a/java/maven/test/unit/data/projects/multiproject/democa/LICENSE b/java/maven/test/unit/data/projects/multiproject/democa/LICENSE new file mode 100644 index 000000000000..20e4bd85661f --- /dev/null +++ b/java/maven/test/unit/data/projects/multiproject/democa/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed 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 + + https://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. diff --git a/java/maven/test/unit/data/projects/multiproject/democa/lib/pom.xml b/java/maven/test/unit/data/projects/multiproject/democa/lib/pom.xml new file mode 100644 index 000000000000..6d19155a44fe --- /dev/null +++ b/java/maven/test/unit/data/projects/multiproject/democa/lib/pom.xml @@ -0,0 +1,198 @@ + + + + 4.0.0 + com.exampleca + lib + 1.0-SNAPSHOT + jar + + + com.exampleca + democa-parent + 1.0-SNAPSHOT + + + + jar + 17 + 17 + 4.0.3-oracle-00001 + + + + + central + https://repo.maven.apache.org/maven2 + + + + gcn + https://maven.oracle.com/public + + + + + + + cloud.graal.gcn + gcn-bom + 2.0 + pom + import + + + + + + io.micronaut + micronaut-inject + compile + + + io.micronaut.validation + micronaut-validation + compile + + + io.micronaut + micronaut-http-client + compile + + + io.micronaut + micronaut-http-server-netty + compile + + + io.micronaut.data + micronaut-data-jdbc + compile + + + io.micronaut.objectstorage + micronaut-object-storage-core + compile + + + io.micronaut.objectstorage + micronaut-object-storage-oracle-cloud + compile + + + io.micronaut.oraclecloud + micronaut-oraclecloud-atp + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + io.micronaut.sql + micronaut-jdbc-hikari + compile + + + jakarta.validation + jakarta.validation-api + compile + + + ch.qos.logback + logback-classic + runtime + + + io.micronaut + micronaut-http-server + provided + + + io.micronaut.testresources + micronaut-test-resources-client + provided + + + io.micronaut.test + micronaut-test-junit5 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + + ${basedir}/src/main/resources + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.micronaut + micronaut-inject-java + ${micronaut.core.version} + + + io.micronaut.data + micronaut-data-processor + ${micronaut.data.version} + + + io.micronaut + micronaut-graal + ${micronaut.core.version} + + + io.micronaut.serde + micronaut-serde-processor + ${micronaut.serialization.version} + + + io.micronaut.validation + micronaut-validation-processor + ${micronaut.validation.version} + + + + + + + + diff --git a/java/maven/test/unit/data/projects/multiproject/democa/oci/pom.xml b/java/maven/test/unit/data/projects/multiproject/democa/oci/pom.xml new file mode 100644 index 000000000000..e1c7953baaed --- /dev/null +++ b/java/maven/test/unit/data/projects/multiproject/democa/oci/pom.xml @@ -0,0 +1,253 @@ + + + + 4.0.0 + com.exampleca + oci + 1.0-SNAPSHOT + ${packaging} + democa-${artifactId} + + + com.exampleca + democa-parent + 1.0-SNAPSHOT + + + jar + 17 + 17 + 4.0.3-oracle-00001 + true + netty + com.exampleca.Application + + + + + central + https://repo.maven.apache.org/maven2 + + + + gcn + https://maven.oracle.com/public + + + + + + + cloud.graal.gcn + gcn-bom + 2.0 + pom + import + + + + + + com.oracle.oci.sdk + oci-java-sdk-addons-graalvm + compile + + + io.micronaut + micronaut-http-client + compile + + + io.micronaut + micronaut-http-server-netty + compile + + + io.micronaut.data + micronaut-data-jdbc + compile + + + io.micronaut.flyway + micronaut-flyway + compile + + + io.micronaut.objectstorage + micronaut-object-storage-oracle-cloud + compile + + + io.micronaut.oraclecloud + micronaut-oraclecloud-atp + compile + + + io.micronaut.oraclecloud + micronaut-oraclecloud-httpclient-netty + compile + + + io.micronaut.oraclecloud + micronaut-oraclecloud-sdk + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + io.micronaut.sql + micronaut-jdbc-hikari + compile + + + io.micronaut.validation + micronaut-validation + compile + + + jakarta.validation + jakarta.validation-api + compile + + + ch.qos.logback + logback-classic + runtime + + + org.flywaydb + flyway-database-oracle + runtime + + + io.micronaut.testresources + micronaut-test-resources-client + provided + + + io.micronaut.test + micronaut-test-junit5 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.mockito + mockito-core + test + + + com.exampleca + lib + 1.0-SNAPSHOT + compile + + + + + + com.google.cloud.tools + jib-maven-plugin + + + ${project.name} + + + + + io.micronaut.maven + micronaut-maven-plugin + + frolvlad/alpine-glibc:alpine-3.16 + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + io.micronaut + micronaut-inject-java + ${micronaut.core.version} + + + io.micronaut.data + micronaut-data-processor + ${micronaut.data.version} + + + io.micronaut + micronaut-inject + + + + + io.micronaut + micronaut-graal + ${micronaut.core.version} + + + io.micronaut.serde + micronaut-serde-processor + ${micronaut.serialization.version} + + + io.micronaut + micronaut-inject + + + + + io.micronaut.validation + micronaut-validation-processor + ${micronaut.validation.version} + + + io.micronaut + micronaut-inject + + + + + + + + + + diff --git a/java/maven/test/unit/data/projects/multiproject/democa/pom.xml b/java/maven/test/unit/data/projects/multiproject/democa/pom.xml new file mode 100644 index 000000000000..7611c2999e79 --- /dev/null +++ b/java/maven/test/unit/data/projects/multiproject/democa/pom.xml @@ -0,0 +1,50 @@ + + + + 4.0.0 + + io.micronaut.platform + micronaut-parent + 4.0.3-oracle-00001 + + + + central + https://repo.maven.apache.org/maven2 + + + gcn + https://maven.oracle.com/public + + + democa-parent + 1.0-SNAPSHOT + com.exampleca + democa + pom + + + lib + oci + + diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImpl2Test.java b/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImpl2Test.java new file mode 100644 index 000000000000..62cbe2c31d52 --- /dev/null +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImpl2Test.java @@ -0,0 +1,597 @@ +/* + * 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.maven; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import static junit.framework.TestCase.assertEquals; +import static junit.framework.TestCase.assertTrue; +import org.junit.Assume; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.junit.NbTestCase; +import org.netbeans.modules.maven.api.NbMavenProject; +import org.netbeans.modules.maven.api.execute.ExecutionContext; +import org.netbeans.modules.maven.api.execute.LateBoundPrerequisitesChecker; +import org.netbeans.modules.maven.api.execute.RunConfig; +import org.netbeans.modules.maven.embedder.EmbedderFactory; +import org.netbeans.modules.maven.execute.MavenExecMonitor; +import org.netbeans.spi.project.ActionProgress; +import org.netbeans.spi.project.ActionProvider; +import org.netbeans.spi.project.ProjectServiceProvider; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileUtil; +import org.openide.modules.DummyInstalledFileLocator; +import org.openide.util.Pair; +import org.openide.util.RequestProcessor; +import org.openide.util.RequestProcessor.Task; +import org.openide.util.lookup.Lookups; +import org.openide.util.test.MockLookup; +import org.openide.windows.IOProvider; + +public class NbMavenProjectImpl2Test extends NbTestCase { + public NbMavenProjectImpl2Test(String name) { + super(name); + + } + + private FileObject wd; + private File repo; + private FileObject repoFO; + private FileObject dataFO; + + private static File getTestNBDestDir() { + String destDir = System.getProperty("test.netbeans.dest.dir"); + // set in project.properties as test-unit-sys-prop.test.netbeans.dest.dir + assertNotNull("test.netbeans.dest.dir property has to be set when running within binary distribution", destDir); + return new File(destDir); + } + + protected @Override void setUp() throws Exception { + // this property could be eventually initialized by NB module system, as MavenCacheDisabler i @OnStart, but that's unreliable. + System.setProperty("maven.defaultProjectBuilder.disableGlobalModelCache", "true"); + + clearWorkDir(); + + wd = FileUtil.toFileObject(getWorkDir()); + //synchronous reload of maven project asserts sanoty in some tests.. + System.setProperty("test.reload.sync", "false"); + + // This is needed, otherwose the core window's startup code will redirect + // System.out/err to the IOProvider, and its Trivial implementation will redirect + // it back to System.err - loop is formed. Initialize IOProvider first, it gets + // the real System.err/out references. + IOProvider p = IOProvider.getDefault(); + + repo = EmbedderFactory.getProjectEmbedder().getLocalRepositoryFile(); + repoFO = FileUtil.toFileObject(repo); + dataFO = FileUtil.toFileObject(getDataDir()); + + // Configure the DummyFilesLocator with NB harness dir + File destDirF = getTestNBDestDir(); + DummyInstalledFileLocator.registerDestDir(destDirF); + + useTestJdk = true; + } + + @Override + protected void tearDown() throws Exception { + useTestJdk = false; + super.tearDown(); + } + + + + protected @Override Level logLevel() { + return Level.FINE; + } + + protected @Override String logRoot() { + return "org.netbeans.modules.maven"; + } + + volatile static boolean useTestJdk; + + /** + * Forces Maven execution on the test JDK. Should not affect other classes. This is significant + * on the developer's machine with multiple JDKs installed. Not so interesting on CI. + */ + @ProjectServiceProvider(projectType = NbMavenProject.TYPE, service = LateBoundPrerequisitesChecker.class) + public static class JdkChecker implements LateBoundPrerequisitesChecker { + @Override + public boolean checkRunConfig(RunConfig config, ExecutionContext con) { + if (useTestJdk) { + config.setProperty("Env.JAVA_HOME", System.getProperty("java.home")); + } + return true; + } + } + + private void cleanMavenRepository() throws IOException { + Path path = Paths.get(System.getProperty("user.home"), ".m2", "repository"); + if (!Files.isDirectory(path)) { + return; + } + FileUtil.toFileObject(path.toFile()).delete(); + } + + /** + * Primes the project including dependency fetch, waits for the operation to complete. + * @throws Exception + */ + void primeProject(Project p) throws Exception { + ActionProvider ap = p.getLookup().lookup(ActionProvider.class); + if (ap == null) { + throw new IllegalStateException("No action provider"); + } + assertTrue(Arrays.asList(ap.getSupportedActions()).contains(ActionProvider.COMMAND_PRIME)); + + CountDownLatch primeLatch = new CountDownLatch(1); + ActionProgress prg = new ActionProgress() { + @Override + protected void started() { + } + + @Override + public void finished(boolean success) { + primeLatch.countDown(); + } + }; + ap.invokeAction(ActionProvider.COMMAND_PRIME, Lookups.fixed(prg)); + primeLatch.await(300, TimeUnit.SECONDS); + } + + MavenExecMonitor mme; + + Project reloadProject; + NbMavenProjectImpl reloadProjectImpl; + + AtomicInteger projectEventCount = new AtomicInteger(); + CompletableFuture event = new CompletableFuture<>(); + CompletableFuture task = new CompletableFuture<>(); + + + private void reloadProjectSetup() throws Exception { + clearWorkDir(); + + FileObject testApp = dataFO.getFileObject("parent-projects/single"); + FileObject prjCopy = FileUtil.copyFile(testApp, FileUtil.toFileObject(getWorkDir()), "simpleProject"); + + + Project p = ProjectManager.getDefault().findProject(prjCopy); + assertNotNull(p); + NbMavenProjectImpl impl = p.getLookup().lookup(NbMavenProjectImpl.class); + + Pair, Task> blockState = impl.reloadBlockingState(); + assertTrue(blockState.first().isEmpty()); + assertNull(blockState.second()); + + reloadProject = p; + reloadProjectImpl = impl; + + NbMavenProject.addPropertyChangeListener(reloadProject, (e) -> { + if (NbMavenProject.PROP_PROJECT.equals(e.getPropertyName())) { + projectEventCount.incrementAndGet(); + event.complete(null); + } + }); + } + + // Let's have per-testcase RP, so an eventually dangling task does not ruin other testcases. + private final RequestProcessor processor = new RequestProcessor(NbMavenProjectImplTest.class); + + private List asyncThrowable = Collections.synchronizedList(new ArrayList<>()); + + private void recordAsync(Throwable t) { + asyncThrowable.add(t); + } + + public void testProjectReloadsSchedulesTask() throws Exception { + reloadProjectSetup(); + AtomicBoolean firedAtCompletion = new AtomicBoolean(); + + // blocks the reload task from completing + synchronized (reloadProjectImpl) { + assertTrue("Project must not be reloading", reloadProjectImpl.getReloadTask().isFinished()); + + Task t = reloadProjectImpl.fireProjectReload(true); + t.addTaskListener((e) -> { + firedAtCompletion.set(event.isDone()); + task.complete(e); + }); + + assertFalse("Project reload started", reloadProjectImpl.getReloadTask().isFinished()); + } + + CompletableFuture.allOf(event, task).get(10, TimeUnit.SECONDS); + assertTrue("Project event fired before task completion", firedAtCompletion.get()); + } + + /** + * Checks that the project reload is NOT planned after fireProjectReload(true), if there's a blocking task. Then it checks, + * that completing the blocker, the reload task gets scheduled and completes. + */ + public void testProjectOperationDelaysReload() throws Exception { + reloadProjectSetup(); + + AtomicBoolean firedAtCompletion = new AtomicBoolean(); + CountDownLatch blocker = new CountDownLatch(1); + RequestProcessor.Task blockerTask = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + + Task reloadTask; + synchronized (reloadProjectImpl) { + assertTrue("Project must not be reloading", reloadProjectImpl.getReloadTask().isFinished()); + + reloadTask = reloadProjectImpl.fireProjectReload(true); + assertTrue("Reload task must not start with active blockers", reloadProjectImpl.getReloadTask().isFinished()); + } + + Thread.sleep(1000); + assertTrue("Reload task must not start with active blockers", reloadProjectImpl.getReloadTask().isFinished()); + + CountDownLatch delay1 = new CountDownLatch(1); + + // the blocker tasks's listener already present should eventually release / schedule reload task, so + // this listener should get an already scheduled task. + blockerTask.addTaskListener((e) -> { + reloadTask.addTaskListener((e2) -> { + firedAtCompletion.set(event.isDone()); + task.complete(e); + }); + delay1.countDown(); + }); + + // unblock the task + blocker.countDown(); + + delay1.await(); + + try { + task.get(10, TimeUnit.SECONDS); + } catch (TimeoutException e) { + fail("Reload was not scheduled"); + } + + assertTrue("Project event fired before task completion", firedAtCompletion.get()); + } + + /** + * Checks that reload that ignores blockers completes regardless of blockers still unfinished. + */ + public void testForcedReloadBypassesBlockers() throws Exception { + reloadProjectSetup(); + + CountDownLatch blocker = new CountDownLatch(1); + + AtomicReference reloadTask = new AtomicReference<>(); + + RequestProcessor.Task blockerTask = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + synchronized (reloadProjectImpl) { + assertTrue("Project must not be reloading", reloadProjectImpl.getReloadTask().isFinished()); + reloadTask.set(reloadProjectImpl.fireProjectReload(false)); + assertFalse("Forced reload should be scheduled immediately", reloadProjectImpl.getReloadTask().isFinished()); + } + + assertTrue("Reload finished despite blockers", reloadTask.get().waitFinished(10 * 1000)); + assertFalse(blockerTask.isFinished()); + + blockerTask.cancel(); + } + + /** + * Force-reload should not clean the blocker list. + */ + public void testForcedReloadKeepsWaiters() throws Exception { + reloadProjectSetup(); + + CountDownLatch blocker = new CountDownLatch(1); + AtomicReference reloadTask = new AtomicReference<>(); + reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + synchronized (reloadProjectImpl) { + assertTrue("Project must not be reloading", reloadProjectImpl.getReloadTask().isFinished()); + reloadTask.set(reloadProjectImpl.fireProjectReload(false)); + assertFalse("Forced reload should be scheduled immediately", reloadProjectImpl.getReloadTask().isFinished()); + } + + + Pair, Task> blockState = reloadProjectImpl.reloadBlockingState(); + assertFalse(blockState.first().isEmpty()); + assertNull("No soft-reload was requested", blockState.second()); + reloadProjectImpl.fireProjectReload(true); + blockState = reloadProjectImpl.reloadBlockingState(); + assertNotNull("Soft-reload requested, completion task must have been created", blockState.second()); + blocker.countDown(); + } + + /** + * Reload is called several times while blocked. Should happen and fire just once after unblocking. + */ + public void testDelayedReloadTwiceHappensOnce() throws Exception { + reloadProjectSetup(); + + CountDownLatch blocker = new CountDownLatch(1); + Task reloadTask1; + Task reloadTask2; + reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + assertTrue("Project must not be reloading", reloadProjectImpl.getReloadTask().isFinished()); + reloadTask1 = reloadProjectImpl.fireProjectReload(true); + reloadTask2 = reloadProjectImpl.fireProjectReload(true); + + blocker.countDown(); + + reloadTask1.waitFinished(10 * 1000); + reloadTask2.waitFinished(10 * 1000); + + assertEquals("Reload must complete exactly once", 1, this.projectEventCount.get()); + } + + public void testForcedReloadReloadsAgainAfterBlockersComplete() throws Exception { + reloadProjectSetup(); + CountDownLatch blocker = new CountDownLatch(1); + + reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + Task reloadTask1; + Task reloadTask2; + reloadTask1 = reloadProjectImpl.fireProjectReload(true); + // now force-reload + reloadTask2 = reloadProjectImpl.fireProjectReload(false); + + reloadTask2.waitFinished(); + + assertEquals("The force-reload must complete and fire", 1, projectEventCount.get()); + blocker.countDown(); + + reloadTask1.waitFinished(); + assertEquals("The reload scheduled during blocker must run separately", 2, projectEventCount.get()); + } + + public void testDoubleBlockersReleaseAtEnd() throws Exception { + reloadProjectSetup(); + + CountDownLatch blocker = new CountDownLatch(1); + CountDownLatch blocker2 = new CountDownLatch(1); + + Task b1 = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + Task b2 = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker2.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + + Pair, Task> blockState = reloadProjectImpl.reloadBlockingState(); + assertEquals("Two blockers are registered", 2, blockState.first().size()); + + RequestProcessor.Task t; + synchronized (reloadProjectImpl) { + t = reloadProjectImpl.fireProjectReload(true); + assertFalse(t.isFinished()); + } + + blocker.countDown(); + assertFalse("Blocked reload should be still unscheduled", t.waitFinished(300)); + blocker2.countDown(); + t.waitFinished(10 * 1000); + assertTrue(b1.isFinished()); + assertTrue(b2.isFinished()); + assertEquals("Project events must fire once", 1, projectEventCount.get()); + } + + public void testCompleteBlockersWithoutReloadDoesNotReload() throws Exception { + reloadProjectSetup(); + + CountDownLatch blocker = new CountDownLatch(1); + CountDownLatch blocker2 = new CountDownLatch(1); + + Task b1 = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + Task b2 = reloadProjectImpl.scheduleProjectOperation(processor, () -> { + try { + blocker2.await(); + } catch (InterruptedException ex) { + throw new RuntimeException(ex); + } + }, 0); + + + Pair, Task> blockState = reloadProjectImpl.reloadBlockingState(); + assertEquals(2, blockState.first().size()); + + blocker.countDown(); + blocker2.countDown(); + b1.waitFinished(10 * 1000); + b2.waitFinished(10 * 1000); + + blockState = reloadProjectImpl.reloadBlockingState(); + assertEquals(0, blockState.first().size()); + assertEquals(0, projectEventCount.get()); + } + + /** + * Checks that subproject reload after the subproject primes. + */ + public void testSubprojectsReloadAfterPriming() throws Exception { + cleanMavenRepository(); + clearWorkDir(); + + FileUtil.toFileObject(getWorkDir()).refresh(); + + FileObject testApp = dataFO.getFileObject("projects/multiproject/democa"); + FileObject prjCopy = FileUtil.copyFile(testApp, FileUtil.toFileObject(getWorkDir()), "simpleProject"); + + Project p = ProjectManager.getDefault().findProject(prjCopy); + assertNotNull(p); + + Project sub = ProjectManager.getDefault().findProject(prjCopy.getFileObject("lib")); + assertNotNull(sub); + + // check the project's validity: + NbMavenProject subMaven = sub.getLookup().lookup(NbMavenProject.class); + assertTrue("Fallback parent project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + assertTrue("Fallback subproject project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + + primeProject(sub); + assertFalse("Subproject must recover after priming itself", NbMavenProject.isIncomplete(subMaven.getMavenProject())); + } + + /** + * Checks that Priming action on a subproject actually runs on a reactor with --auto-make to build the subproject. + * @throws Exception + */ + public void testSubprojectPrimeRunsReactor() throws Exception { + cleanMavenRepository(); + clearWorkDir(); + + mme = new MavenExecMonitor(); + MockLookup.setLayersAndInstances(mme); + + FileUtil.toFileObject(getWorkDir()).refresh(); + + FileObject testApp = dataFO.getFileObject("projects/multiproject/democa"); + FileObject prjCopy = FileUtil.copyFile(testApp, FileUtil.toFileObject(getWorkDir()), "simpleProject"); + + Project p = ProjectManager.getDefault().findProject(prjCopy); + assertNotNull(p); + + Project sub = ProjectManager.getDefault().findProject(prjCopy.getFileObject("lib")); + assertNotNull(sub); + + // check the project's validity: + NbMavenProject subMaven = sub.getLookup().lookup(NbMavenProject.class); + assertTrue("Fallback parent project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + assertTrue("Fallback subproject project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + + primeProject(sub); + + assertEquals("Just single maven executed:", 1, mme.builders.size()); + + ProcessBuilder b = mme.builders.getFirst(); + assertEquals("Runs in root project's dir", FileUtil.toFile(prjCopy), b.directory()); + assertTrue("Specifies also-make", b.command().indexOf("--also-make") > 0); + int idx = b.command().indexOf("--projects"); + assertTrue("Specifies projects", idx > 0); + assertEquals("Runs up to the lib subprojectsd", "lib", b.command().get(idx + 1)); + } + + /** + * Checks that subproject reload after its parent project primes. + */ + public void testSubprojectsReloadAfterParentPriming() throws Exception { + String jv = System.getProperty("java.specification.version"); + Assume.assumeTrue("Need JDK17", !jv.startsWith("1.") && Integer.parseInt(jv) >= 17); + cleanMavenRepository(); + clearWorkDir(); + + FileUtil.toFileObject(getWorkDir()).refresh(); + + FileObject testApp = dataFO.getFileObject("projects/multiproject/democa"); + FileObject prjCopy = FileUtil.copyFile(testApp, FileUtil.toFileObject(getWorkDir()), "simpleProject"); + + Project p = ProjectManager.getDefault().findProject(prjCopy); + assertNotNull(p); + + Project sub = ProjectManager.getDefault().findProject(prjCopy.getFileObject("lib")); + assertNotNull(sub); + + // check the project's validity: + NbMavenProject parentMaven = p.getLookup().lookup(NbMavenProject.class); + NbMavenProject subMaven = sub.getLookup().lookup(NbMavenProject.class); + assertTrue("Fallback parent project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + assertTrue("Fallback subproject project is expected on unpopulated repository", NbMavenProject.isErrorPlaceholder(subMaven.getMavenProject())); + + primeProject(p); + // subprojects are reloaded asynchronously. Watch out for child project's property for some time. + CountDownLatch latch = new CountDownLatch(1); + subMaven.addPropertyChangeListener((e) -> { + if (NbMavenProject.PROP_PROJECT.equals(e.getPropertyName())) { + latch.countDown(); + } + }); + latch.await(10, TimeUnit.SECONDS); + assertFalse("Subproject must recover after priming the parent", NbMavenProject.isIncomplete(subMaven.getMavenProject())); + } +} diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImplTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImplTest.java index 5106ae265274..d2db62b8d349 100644 --- a/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImplTest.java +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/NbMavenProjectImplTest.java @@ -22,6 +22,9 @@ import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.Collections; import java.util.Set; import java.util.TreeSet; diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecMonitor.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecMonitor.java new file mode 100644 index 000000000000..d7b3761bae51 --- /dev/null +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MavenExecMonitor.java @@ -0,0 +1,50 @@ +/* + * 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.maven.execute; + +import java.util.concurrent.ConcurrentLinkedDeque; +import org.netbeans.modules.maven.api.execute.RunConfig; +import org.openide.windows.InputOutput; + +/** + * + * @author sdedic + */ +public class MavenExecMonitor extends MavenCommandLineExecutor.ExecuteMaven { + public ConcurrentLinkedDeque builders = new ConcurrentLinkedDeque<>(); + + @Override + MavenExecutor createCommandLineExecutor(RunConfig config, InputOutput io, AbstractMavenExecutor.TabContext tc) { + return new CmdlineExecutor(config, io, tc); + } + + class CmdlineExecutor extends MavenCommandLineExecutor { + + public CmdlineExecutor(RunConfig conf, InputOutput io, TabContext tc) { + super(conf, io, tc); + } + + @Override + ProcessBuilder constructBuilder(RunConfig clonedConfig, InputOutput ioput) { + ProcessBuilder b = super.constructBuilder(clonedConfig, ioput); + builders.add(b); + return b; + } + } +} diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MockMavenExec.java b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MockMavenExec.java index cf1217e9a4ae..03e4367210f6 100644 --- a/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MockMavenExec.java +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/execute/MockMavenExec.java @@ -28,14 +28,23 @@ */ public class MockMavenExec extends MavenCommandLineExecutor.ExecuteMaven { - public volatile boolean executed; - public volatile RunConfig executedConfig; - public CountDownLatch executedLatch = new CountDownLatch(1); + public static class Reporter { + public volatile boolean executed; + public volatile RunConfig executedConfig; + public CountDownLatch executedLatch = new CountDownLatch(1); + + public void executed(RunConfig config) { + executed = true; + executedConfig = config; + } + } @Override public ExecutorTask execute(RunConfig config, InputOutput io, AbstractMavenExecutor.TabContext tc) { - executed = true; - executedConfig = config; + Reporter r = config.getActionContext().lookup(Reporter.class); + if (r != null) { + r.executed(config); + } ExecutorTask t = new ExecutorTask(() -> { }) { @Override @@ -53,7 +62,9 @@ public InputOutput getInputOutput() { } }; t.run(); - executedLatch.countDown(); + if (r != null) { + r.executedLatch.countDown(); + } return t; } diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/problems/PrimingActionTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/problems/PrimingActionTest.java index 60d6dab6cdf5..f49a5090500a 100644 --- a/java/maven/test/unit/src/org/netbeans/modules/maven/problems/PrimingActionTest.java +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/problems/PrimingActionTest.java @@ -172,13 +172,13 @@ public void testActionNotEnabledOnOKProject() throws Exception { assertFalse(enabled); } - /** * Checks that the priming build does not actually run on OK project, although * the action may be temporarily enabled. */ public void testPrimingBuildNotRunOnOK() throws Exception { MockMavenExec mme = new MockMavenExec(); + MockMavenExec.Reporter r = new MockMavenExec.Reporter(); MockLookup.setLayersAndInstances(mme); CountDownLatch cdl = new CountDownLatch(1); MavenModelProblemsProvider.RP.submit(() -> { @@ -194,7 +194,8 @@ public void testPrimingBuildNotRunOnOK() throws Exception { Collection probs = collectProblems(p); assertEquals(0, probs.size()); ActionProvider ap = p.getLookup().lookup(ActionProvider.class); - boolean enabled = ap.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookup.EMPTY); + + boolean enabled = ap.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookups.fixed(r)); // the actual detection is still broken. assertTrue(enabled); @@ -228,7 +229,7 @@ public void finished(boolean success) { assertTrue(progress.finished); // but the execution was NOT really done - assertFalse(mme.executed); + assertFalse(r.executed); // check that the action is now disabled. assertFalse(ap.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookup.EMPTY)); @@ -244,12 +245,13 @@ public void testPrimingBuildExecutes() throws Exception { System.setProperty("test.reload.sync", "true"); + MockMavenExec.Reporter r = new MockMavenExec.Reporter(); setupBrokenProject(); Project p = ProjectManager.getDefault().findProject(FileUtil.toFileObject(getWorkDir())); Collection probs = collectProblems(p); assertEquals(1, probs.size()); ActionProvider ap = p.getLookup().lookup(ActionProvider.class); - boolean enabled = ap.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookup.EMPTY); + boolean enabled = ap.isActionEnabled(ActionProvider.COMMAND_PRIME, Lookups.fixed(r)); assertTrue(enabled); class Prog extends ActionProgress { CountDownLatch finish = new CountDownLatch(1); @@ -270,10 +272,10 @@ public void finished(boolean success) { Prog progress = new Prog(); - ap.invokeAction(ActionProvider.COMMAND_PRIME, Lookups.fixed(progress)); + ap.invokeAction(ActionProvider.COMMAND_PRIME, Lookups.fixed(progress, r)); progress.finish.await(); // but the execution was NOT really done - assertTrue(mme.executed); + assertTrue(r.executed); } } diff --git a/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java b/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java index d15793e1be20..1183cfe90e71 100644 --- a/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java +++ b/java/maven/test/unit/src/org/netbeans/modules/maven/spi/actions/ProvidedConfigurationsTest.java @@ -241,6 +241,7 @@ public void testContributedProfileActionCanCustomize() throws Exception { */ public void testExampleProviderConfigurationUsage() throws Exception { MockMavenExec mme = new MockMavenExec(); + MockMavenExec.Reporter r = new MockMavenExec.Reporter(); MockLookup.setLayersAndInstances(mme); setupOKProject(); @@ -252,15 +253,15 @@ public void testExampleProviderConfigurationUsage() throws Exception { ProjectConfigurationProvider pcp = p.getLookup().lookup(ProjectConfigurationProvider.class); ProjectConfiguration configToUse = pcp.getConfigurations().stream(). filter(x -> "Micronaut: dev mode".equals(x.getDisplayName())).findAny().get(); - Lookup ctx = Lookups.fixed(theFile, configToUse); + Lookup ctx = Lookups.fixed(theFile, configToUse, r); if (!ap.isActionEnabled(ActionProvider.COMMAND_RUN, ctx)) { // action not enabled return; } ap.invokeAction(ActionProvider.COMMAND_RUN, ctx); - mme.executedLatch.await(); - assertEquals(Arrays.asList("mn:run"), mme.executedConfig.getGoals()); + r.executedLatch.await(); + assertEquals(Arrays.asList("mn:run"), r.executedConfig.getGoals()); } @ProjectServiceProvider(service = MavenActionsProvider.class, projectType = NbMavenProject.TYPE) From 9f51a382436e97dd39653d669472505bbd8af088 Mon Sep 17 00:00:00 2001 From: Svata Dedic Date: Thu, 19 Oct 2023 14:35:33 +0200 Subject: [PATCH 09/11] Include add-opens flags for tests/JDK9+ --- java/java.mx.project/nbproject/project.properties | 2 ++ nbbuild/templates/common.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/java/java.mx.project/nbproject/project.properties b/java/java.mx.project/nbproject/project.properties index c8c37c37829e..2a867ffacd61 100644 --- a/java/java.mx.project/nbproject/project.properties +++ b/java/java.mx.project/nbproject/project.properties @@ -22,3 +22,5 @@ requires.nb.javac=true # For testing we need path to the MX executable. The executable is checked out by the buildscript. test.run.args=-Dorg.netbeans.modules.java.mx.project.test.mxpath=${basedir}/test/unit/data/mx/mx + +test.jms.flags=--add-opens=java.base/java.net=ALL-UNNAMED diff --git a/nbbuild/templates/common.xml b/nbbuild/templates/common.xml index ed6f32c25de1..202bb4130652 100644 --- a/nbbuild/templates/common.xml +++ b/nbbuild/templates/common.xml @@ -736,6 +736,7 @@ + @@ -747,6 +748,7 @@ + From e6ea7501e7e2010e4f056df0df90b3d552228815 Mon Sep 17 00:00:00 2001 From: Laszlo Kishalmi Date: Tue, 24 Oct 2023 19:28:05 +0200 Subject: [PATCH 10/11] Be more friendly on 'runSingle' when 'run' task is missing. --- .../tooling/NetBeansRunSinglePlugin.java | 95 +++++++++---------- 1 file changed, 47 insertions(+), 48 deletions(-) diff --git a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NetBeansRunSinglePlugin.java b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NetBeansRunSinglePlugin.java index e68d0871229c..bf2bb72ac914 100644 --- a/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NetBeansRunSinglePlugin.java +++ b/extide/gradle/netbeans-gradle-tooling/src/main/java/org/netbeans/modules/gradle/tooling/NetBeansRunSinglePlugin.java @@ -30,8 +30,8 @@ import org.gradle.api.Task; import org.gradle.api.tasks.JavaExec; import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.TaskProvider; import org.gradle.process.CommandLineArgumentProvider; -import org.gradle.tooling.BuildException; import org.gradle.util.GradleVersion; /** * @@ -47,6 +47,8 @@ class NetBeansRunSinglePlugin implements Plugin { private static final String RUN_SINGLE_JVM_ARGS = "runJvmArgs"; private static final String RUN_SINGLE_CWD = "runWorkingDir"; + private static final String DEPRECATE_RUN_SINGLE = + "runSingle task is deprecated. Inspect your configuration and use just 'run' task instead of 'runSingle'"; @Override public void apply(Project project) { project.afterEvaluate(p -> { @@ -55,61 +57,58 @@ public void apply(Project project) { && project.hasProperty(RUN_SINGLE_MAIN)) { Set runTasks = p.getTasksByName("run", false); Task r = runTasks.isEmpty() ? null : runTasks.iterator().next(); - String mainClass = project.property(RUN_SINGLE_MAIN).toString(); - p.getTasks().withType(JavaExec.class).configureEach(je -> { - if (GRADLE_VERSION.compareTo(GradleVersion.version("6.4")) < 0) { - // Using setMain to keep the backward compatibility before Gradle 6.4 - je.setMain(mainClass); - } else { - je.getMainClass().set(mainClass); - } - if (project.hasProperty(RUN_SINGLE_ARGS)) { - je.setArgs(asList(project.property(RUN_SINGLE_ARGS).toString().split(" "))); - } - if (p.hasProperty(RUN_SINGLE_JVM_ARGS)) { - // Property jvmArgumentProviders should not be implemented as a lambda to allow execution optimizations. - // See https://docs.gradle.org/current/userguide/validation_problems.html#implementation_unknown - je.getJvmArgumentProviders().add(new CommandLineArgumentProvider() { - // Do not convert to lambda. - @Override - public Iterable asArguments() { - return asList(p.property(RUN_SINGLE_JVM_ARGS).toString().split(" ")); - } - }); - } - try { - je.setStandardInput(System.in); - } catch (RuntimeException ex) { - if(LOG.isEnabled(LogLevel.DEBUG)) { - LOG.debug("Failed to set STDIN for Plugin: " + je.toString(), ex); - } else { - LOG.info("Failed to set STDIN for Plugin: " + je.toString()); - } - } - if (project.hasProperty(RUN_SINGLE_CWD)) { - je.setWorkingDir(project.property(RUN_SINGLE_CWD).toString()); - } - }); + p.getTasks().withType(JavaExec.class).configureEach(je -> configureJavaExec(project, je)); addTask(project, r); } }); } - public static class JE extends JavaExec { - @Override - public void exec() { + private void configureJavaExec(Project project, JavaExec je) { + String mainClass = project.property(RUN_SINGLE_MAIN).toString(); + if (GRADLE_VERSION.compareTo(GradleVersion.version("6.4")) < 0) { + // Using setMain to keep the backward compatibility before Gradle 6.4 + je.setMain(mainClass); + } else { + je.getMainClass().set(mainClass); } - } - - private void addTask(Project project, Task runTask) { - project.getTasks().register(RUN_SINGLE_TASK, JE.class, (je) -> { - if (runTask == null) { - throw new BuildException("Could not find \"run\" task to execute. Please upgrade your configuration to use standard run-style tasks instead of deprecated runSingle", null); + if (project.hasProperty(RUN_SINGLE_ARGS)) { + je.setArgs(asList(project.property(RUN_SINGLE_ARGS).toString().split(" "))); + } + if (project.hasProperty(RUN_SINGLE_JVM_ARGS)) { + // Property jvmArgumentProviders should not be implemented as a lambda to allow execution optimizations. + // See https://docs.gradle.org/current/userguide/validation_problems.html#implementation_unknown + je.getJvmArgumentProviders().add(new CommandLineArgumentProvider() { + // Do not convert to lambda. + @Override + public Iterable asArguments() { + return asList(project.property(RUN_SINGLE_JVM_ARGS).toString().split(" ")); + } + }); + } + try { + je.setStandardInput(System.in); + } catch (RuntimeException ex) { + if(LOG.isEnabled(LogLevel.DEBUG)) { + LOG.debug("Failed to set STDIN for Plugin: " + je.toString(), ex); } else { - LOG.warn("runSingle task is deprecated. Inspect your configuration and use just 'run' task instead of 'runSingle'"); - je.finalizedBy(runTask); + LOG.info("Failed to set STDIN for Plugin: " + je.toString()); } - }); + } + if (project.hasProperty(RUN_SINGLE_CWD)) { + je.setWorkingDir(project.property(RUN_SINGLE_CWD).toString()); + } + } + + private void addTask(Project project, Task runTask) { + TaskProvider runSingle = runTask == null + ? project.getTasks().register(RUN_SINGLE_TASK, JavaExec.class, (je) -> { + SourceSetContainer sourceSets = project.getExtensions().findByType(SourceSetContainer.class); + je.setClasspath(sourceSets.findByName("main").getRuntimeClasspath()); + configureJavaExec(project, je); + }) + : project.getTasks().register(RUN_SINGLE_TASK, DefaultTask.class, (task) -> task.finalizedBy(runTask)); + + runSingle.configure((task) -> task.doFirst((action) -> project.getLogger().warn(DEPRECATE_RUN_SINGLE))); } } From 8ecaee2fd2d86812223ecd534d0f1ede017d0e37 Mon Sep 17 00:00:00 2001 From: Michael Bien Date: Wed, 25 Oct 2023 00:24:19 +0200 Subject: [PATCH 11/11] Naming panel should be set to its preferred size. Allows the layout manager to compute its size properly, esp when a non default font size is configured (e.g --fontsize 16) fixes #6616 (also removes invisible and unused check box) --- .../netbeans/modules/java/ui/FmtNaming.form | 29 +++-------------- .../netbeans/modules/java/ui/FmtNaming.java | 31 +++++-------------- 2 files changed, 12 insertions(+), 48 deletions(-) diff --git a/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.form b/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.form index 67ad4a9601a9..19170ade5754 100644 --- a/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.form +++ b/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.form @@ -46,12 +46,9 @@ - + - - - - + @@ -63,9 +60,7 @@ - - - + @@ -79,22 +74,6 @@ - - - - - - - - - - - - - - - - @@ -227,7 +206,7 @@ - + diff --git a/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.java b/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.java index b1e1222967e2..55b5ece92ad9 100644 --- a/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.java +++ b/java/java.source/src/org/netbeans/modules/java/ui/FmtNaming.java @@ -58,8 +58,6 @@ public class FmtNaming extends javax.swing.JPanel implements Runnable { */ public FmtNaming() { initComponents(); - preferLongerNamesCheckBox.putClientProperty(OPTION_ID, preferLongerNames); - preferLongerNamesCheckBox.setVisible(false); fieldPrefixField.putClientProperty(OPTION_ID, fieldNamePrefix); fieldSuffixField.putClientProperty(OPTION_ID, fieldNameSuffix); staticFieldPrefixField.putClientProperty(OPTION_ID, staticFieldNamePrefix); @@ -71,12 +69,10 @@ public FmtNaming() { } public static PreferencesCustomizer.Factory getController() { - return new PreferencesCustomizer.Factory() { - public PreferencesCustomizer create(Preferences preferences) { - NamingCategorySupport support = new NamingCategorySupport(preferences, new FmtNaming()); - ((Runnable) support.panel).run(); - return support; - } + return (Preferences preferences) -> { + NamingCategorySupport support = new NamingCategorySupport(preferences, new FmtNaming()); + ((Runnable) support.panel).run(); + return support; }; } @@ -90,7 +86,6 @@ private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; namingConventionsLabel = new javax.swing.JLabel(); - preferLongerNamesCheckBox = new javax.swing.JCheckBox(); jPanel1 = new javax.swing.JPanel(); prefixLabel = new javax.swing.JLabel(); suffixLabel = new javax.swing.JLabel(); @@ -112,11 +107,6 @@ private void initComponents() { org.openide.awt.Mnemonics.setLocalizedText(namingConventionsLabel, org.openide.util.NbBundle.getMessage(FmtNaming.class, "LBL_gen_Naming")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(preferLongerNamesCheckBox, org.openide.util.NbBundle.getMessage(FmtNaming.class, "LBL_gen_PreferLongerNames")); // NOI18N - preferLongerNamesCheckBox.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0)); - preferLongerNamesCheckBox.setMargin(new java.awt.Insets(0, 0, 0, 0)); - preferLongerNamesCheckBox.setOpaque(false); - jPanel1.setLayout(new java.awt.GridBagLayout()); org.openide.awt.Mnemonics.setLocalizedText(prefixLabel, org.openide.util.NbBundle.getMessage(FmtNaming.class, "LBL_gen_Prefix")); // NOI18N @@ -219,7 +209,6 @@ private void initComponents() { gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); jPanel1.add(localVarLabel, gridBagConstraints); localVarSuffixField.setColumns(5); @@ -249,9 +238,7 @@ private void initComponents() { .addComponent(namingConventionsLabel) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(preferLongerNamesCheckBox) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 274, javax.swing.GroupLayout.PREFERRED_SIZE))) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -259,9 +246,7 @@ private void initComponents() { .addGroup(layout.createSequentialGroup() .addComponent(namingConventionsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(preferLongerNamesCheckBox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, 144, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -277,7 +262,6 @@ private void initComponents() { private javax.swing.JLabel parameterLabel; private javax.swing.JTextField parameterPrefixField; private javax.swing.JTextField parameterSuffixField; - private javax.swing.JCheckBox preferLongerNamesCheckBox; private javax.swing.JLabel prefixLabel; private javax.swing.JLabel staticFieldLabel; private javax.swing.JTextField staticFieldPrefixField; @@ -297,6 +281,7 @@ private NamingCategorySupport(Preferences preferences, JPanel panel) { new String[]{FmtOptions.blankLinesBeforeFields, "1"}); //NOI18N } + @Override protected void doModification(ResultIterator resultIterator) throws Exception { final CodeStyle codeStyle = codeStyleProducer.create(previewPrefs); WorkingCopy copy = WorkingCopy.get(resultIterator.getParserResult()); @@ -305,7 +290,7 @@ protected void doModification(ResultIterator resultIterator) throws Exception { GeneratorUtilities gu = GeneratorUtilities.get(copy); CompilationUnitTree cut = copy.getCompilationUnit(); ClassTree ct = (ClassTree) cut.getTypeDecls().get(0); - List members = new ArrayList(); + List members = new ArrayList<>(); String name = CodeStyleUtils.addPrefixSuffix("name", codeStyle.getFieldNamePrefix(), codeStyle.getFieldNameSuffix());