Skip to content

Commit

Permalink
Merge pull request #7812 from dbalek/dbalek/micronaut-functions
Browse files Browse the repository at this point in the history
Micronaut support: minor enhancements.
  • Loading branch information
dbalek authored Oct 1, 2024
2 parents bb3e585 + 9a5bac1 commit 5f47772
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/*
* 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.micronaut.commands;

import com.google.gson.JsonPrimitive;
import java.net.MalformedURLException;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import org.apache.maven.project.MavenProject;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.modules.gradle.api.BuildPropertiesSupport;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.netbeans.modules.project.dependency.ProjectReload;
import org.netbeans.spi.lsp.CommandProvider;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.URLMapper;
import org.openide.util.lookup.ServiceProvider;

/**
*
* @author Dusan Balek
*/
@ServiceProvider(service = CommandProvider.class)
public class MicronautGetBuildPropertiesCommand implements CommandProvider {

private static final String GET_BUILD_PROPERTIES = "nbls.micronaut.get.build.properties";

@Override
public Set<String> getCommands() {
return Set.of(GET_BUILD_PROPERTIES);
}

@Override
public CompletableFuture<Object> runCommand(String command, List<Object> arguments) {
final CompletableFuture<Object> future = new CompletableFuture<>();
if (arguments.size() < 2) {
future.completeExceptionally(new IllegalStateException("Expecting project URL and property name as arguments to " + command));
} else {
try {
String uri = ((JsonPrimitive) arguments.get(0)).getAsString();
String propertyName = ((JsonPrimitive) arguments.get(1)).getAsString();
String taskName = arguments.size() > 2 ? ((JsonPrimitive) arguments.get(2)).getAsString() : null;
FileObject fo = URLMapper.findFileObject(java.net.URI.create(uri).toURL());
Project prj = fo != null ? FileOwnerQuery.getOwner(fo) : null;
if (prj != null) {
ProjectReload.withProjectState(prj, ProjectReload.StateRequest.refresh()).thenRun(() -> {
NbMavenProject p = prj.getLookup().lookup(NbMavenProject.class);
MavenProject mvnp = p != null ? p.getMavenProject() : null;
String value = null;
if (mvnp != null) {
value = (String) mvnp.getProperties().get(propertyName);
} else {
BuildPropertiesSupport bps = BuildPropertiesSupport.get(prj);
if (bps != null) {
BuildPropertiesSupport.Property prop = taskName != null ? bps.findTaskProperty(taskName, propertyName) : bps.findExtensionProperty(null, propertyName);
if (prop != null) {
value = prop.getStringValue();
}
}
}
future.complete(value);
}).exceptionally(ex -> {
future.completeExceptionally(ex);
return null;
});
} else {
future.complete(null);
}
} catch (MalformedURLException ex) {
future.completeExceptionally(ex);
}
}
return future;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public CompletableFuture<Object> runCommand(String command, List<Object> argumen
String contentType = getContentType(cc, el, type);
List<VariableElement> fileUploads = new ArrayList<>();
Map<String, VariableElement> body2params = new LinkedHashMap<>();
for (VariableElement param : ((ExecutableElement) el).getParameters()) {
List<? extends VariableElement> parameters = ((ExecutableElement) el).getParameters();
for (VariableElement param : parameters) {
if (param.asType().getKind() == TypeKind.DECLARED
&& "io.micronaut.http.multipart.CompletedFileUpload".contentEquals(((TypeElement) ((DeclaredType) param.asType()).asElement()).getQualifiedName())) {
fileUploads.add(param);
Expand Down Expand Up @@ -127,6 +128,22 @@ public CompletableFuture<Object> runCommand(String command, List<Object> argumen
contentType = "";
}
}
} else {
String functionName = Utils.getOciFunctionName(cc, ((TypeElement) el.getEnclosingElement()).getQualifiedName().toString());
if (functionName != null && functionName.contentEquals(el.getSimpleName())) {
body2params.put("", param);
if (contentType == null) {
TypeMirror tm = param.asType();
if (tm.getKind() == TypeKind.TYPEVAR) {
tm = ((TypeVariable) tm).getUpperBound();
}
if (tm.getKind() == TypeKind.DECLARED && Utils.getAnnotation(((DeclaredType) tm).asElement().getAnnotationMirrors(), "io.micronaut.serde.annotation.Serdeable") != null) {
contentType = "application/json";
} else if (!cc.getTypes().isAssignable(param.asType(), cc.getElements().getTypeElement("java.lang.CharSequence").asType())) {
contentType = "";
}
}
}
}
}
}
Expand All @@ -144,7 +161,9 @@ public CompletableFuture<Object> runCommand(String command, List<Object> argumen
}
sb.append("--mfd--");
} else if (body2params.isEmpty()) {
sb.append("\n\n${").append(cnt.incrementAndGet()).append(":// TODO: Fill the value").append(contentType).append("}");
if (!parameters.isEmpty()) {
sb.append("\n\n${").append(cnt.incrementAndGet()).append(":// TODO: Fill the value").append("}");
}
} else if (body2params.size() == 1 && body2params.keySet().iterator().next().isEmpty()) {
sb.append("\n\n");
fillJSON(cc, 0, null, body2params.values().iterator().next(), sb, cnt);
Expand All @@ -160,7 +179,7 @@ public CompletableFuture<Object> runCommand(String command, List<Object> argumen
}
sb.append('}');
}
future.complete(sb.toString());
future.complete(sb.length() > 0 ? sb.toString() : null);
} else {
future.complete(null);
}
Expand Down Expand Up @@ -188,7 +207,13 @@ private static void fillJSON(CompilationInfo info, int level, String name, Varia
if (tm.getKind() == TypeKind.DECLARED) {
TypeElement te = (TypeElement) ((DeclaredType) tm).asElement();
if ("java.lang.String".contentEquals(te.getQualifiedName())) {
sb.append("\"${").append(cnt.incrementAndGet()).append(':').append(ve.getSimpleName()).append("}\"");
if (name != null) {
sb.append("\"");
}
sb.append("${").append(cnt.incrementAndGet()).append(':').append(ve.getSimpleName()).append('}');
if (name != null) {
sb.append("\"");
}
} else if (Utils.getAnnotation(te.getAnnotationMirrors(), "io.micronaut.serde.annotation.Serdeable") != null) {
sb.append("{\n");
if (level > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import javax.lang.model.type.TypeVariable;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import org.apache.maven.project.MavenProject;

import org.netbeans.api.editor.mimelookup.MimeLookup;
import org.netbeans.api.java.classpath.ClassPath;
Expand All @@ -71,8 +72,12 @@
import org.netbeans.api.lsp.TextDocumentEdit;
import org.netbeans.api.lsp.TextEdit;
import org.netbeans.api.lsp.WorkspaceEdit;
import org.netbeans.api.project.FileOwnerQuery;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.gradle.api.BuildPropertiesSupport;
import org.netbeans.modules.j2ee.core.api.support.java.GenerationUtils;
import org.netbeans.modules.maven.api.NbMavenProject;
import org.openide.filesystems.FileObject;
import org.openide.util.Union2;
import org.openide.util.WeakListeners;
Expand Down Expand Up @@ -517,6 +522,31 @@ public static VariableElement getIdElement(List<? extends VariableElement> eleme
return null;
}

public static String getOciFunctionName(CompilationInfo info, String className) {
Project prj = FileOwnerQuery.getOwner(info.getFileObject());
if (prj != null) {
String property = null;
NbMavenProject p = prj.getLookup().lookup(NbMavenProject.class);
MavenProject mvnp = p != null ? p.getMavenProject() : null;
if (mvnp != null) {
property = (String) mvnp.getProperties().get("function.entrypoint");
} else {
BuildPropertiesSupport bps = BuildPropertiesSupport.get(prj);
if (bps != null) {
BuildPropertiesSupport.Property prop = bps.findTaskProperty("dockerfile", "defaultCommand");
property = prop != null ? prop.getStringValue() : null;
}
}
if (property != null && property.startsWith(className)) {
String name = property.substring(className.length());
if (name.startsWith("::")) {
return name.substring(2);
}
}
}
return null;
}

private static List<? extends VariableTree> getControllerDataEndpointParams(WorkingCopy copy, ExecutableElement delegateMethod, ExecutableType type) {
TreeMaker tm = copy.getTreeMaker();
GenerationUtils gu = GenerationUtils.newInstance(copy);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ProjectUtils;
import org.netbeans.api.project.SourceGroup;
import org.netbeans.modules.micronaut.db.Utils;
import org.netbeans.modules.parsing.api.Snapshot;
import org.netbeans.modules.parsing.spi.Parser;
import org.netbeans.modules.parsing.spi.indexing.Context;
Expand Down Expand Up @@ -109,6 +110,8 @@ public final class MicronautSymbolFinder extends EmbeddingIndexer implements Pro
private static final String MANAGEMENT_WRITE_ANNOTATION = "io.micronaut.management.endpoint.annotation.Write";
private static final String MANAGEMENT_DELETE_ANNOTATION = "io.micronaut.management.endpoint.annotation.Delete";
private static final String MANAGEMENT_SELECTOR_ANNOTATION = "io.micronaut.management.endpoint.annotation.Selector";
private static final String AWS_FUNCTION = "io.micronaut.function.aws.MicronautRequestHandler";
private static final String OCI_FUNCTION = "io.micronaut.oraclecloud.function.OciFunction";

private final Map<FileObject, Boolean> map = new WeakHashMap<>();
private final Map<ClasspathInfo, List<ClassSymbolLocation>> cache = new WeakHashMap<>();
Expand Down Expand Up @@ -151,20 +154,28 @@ private synchronized boolean initialize(CompilationController cc) {
if (ret == null) {
ClassPath cp = ClassPath.getClassPath(root, ClassPath.COMPILE);
cp.addPropertyChangeListener(WeakListeners.propertyChange(this, cp));
ret = cp.findResource("io/micronaut/http/annotation/HttpMethodMapping.class") != null
|| cp.findResource("io/micronaut/management/endpoint/annotation/Endpoint.class") != null;
ret = resolveClassName(cp, HTTP_METHOD_MAPPING_ANNOTATION, MANAGEMENT_ENDPOINT_ANNOTATION, AWS_FUNCTION, OCI_FUNCTION);
map.put(root, ret);
}
return ret;
}
}
return false;
}
private static boolean resolveClassName(ClassPath cp, String... fqns) {
for (String fqn : fqns) {
if (cp.findResource(fqn.replace('.', '/') + ".class") != null) {
return true;
}
}
return false;
}

public static List<SymbolLocation> scan(CompilationController cc, boolean selectEndpointAnnotation) {
final List<SymbolLocation> ret = new ArrayList<>();
SourcePositions sp = cc.getTrees().getSourcePositions();
TreePathScanner<Void, String> scanner = new TreePathScanner<Void, String>() {
private String functionName = null;
@Override
public Void visitClass(ClassTree node, String path) {
TreePath treePath = this.getCurrentPath();
Expand All @@ -182,15 +193,27 @@ public Void visitClass(ClassTree node, String path) {
} else {
path = getPath((TypeElement) cls);
}
TypeElement ociFunctionTE = cc.getElements().getTypeElement(OCI_FUNCTION);
if (ociFunctionTE != null && cc.getTypes().isSubtype(cc.getTypes().erasure(cls.asType()), ociFunctionTE.asType())) {
functionName = Utils.getOciFunctionName(cc, ((TypeElement) cls).getQualifiedName().toString());
}
TypeElement awsFunctionTE = cc.getElements().getTypeElement(AWS_FUNCTION);
if (awsFunctionTE != null && cc.getTypes().isSubtype(cc.getTypes().erasure(cls.asType()), awsFunctionTE.asType())) {
functionName = "handleRequest";
}
}
return super.visitClass(node, path);
}

@Override
public Void visitMethod(MethodTree node, String path) {
if (path != null) {
TreePath treePath = this.getCurrentPath();
MthIterator it = new MthIterator(cc.getTrees().getElement(treePath), cc.getElements(), cc.getTypes());
TreePath treePath = this.getCurrentPath();
if (functionName != null && functionName.contentEquals(node.getName())) {
int[] span = cc.getTreeUtilities().findNameSpan(node);
ret.add(new SymbolLocation("@/ -- POST", (int) sp.getStartPosition(treePath.getCompilationUnit(), node), (int) sp.getEndPosition(treePath.getCompilationUnit(), node), span[0], span[1]));
} else if (path != null) {
Element mth = cc.getTrees().getElement(treePath);
MthIterator it = new MthIterator(mth, cc.getElements(), cc.getTypes());
while (it.hasNext()) {
ExecutableElement ee = it.next();
for (AnnotationMirror ann : ee.getAnnotationMirrors()) {
Expand Down
10 changes: 5 additions & 5 deletions java/java.lsp.server/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -824,11 +824,11 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
}
}
}));
context.subscriptions.push(commands.registerCommand('nbls.workspace.symbols', async (query) => {
context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.symbols', async (query) => {
const c = await client;
return (await c.sendRequest<SymbolInformation[]>('workspace/symbol', { 'query': query })) ?? [];
}));
context.subscriptions.push(commands.registerCommand('nbls.workspace.symbol.resolve', async (symbol) => {
context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.workspace.symbol.resolve', async (symbol) => {
const c = await client;
return (await c.sendRequest<SymbolInformation>('workspaceSymbol/resolve', symbol)) ?? null;
}));
Expand All @@ -842,15 +842,15 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {
context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.startup.condition', async () => {
return client;
}));
context.subscriptions.push(commands.registerCommand('nbls.addEventListener', (eventName, listener) => {
context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.addEventListener', (eventName, listener) => {
let ls = listeners.get(eventName);
if (!ls) {
ls = [];
listeners.set(eventName, ls);
}
ls.push(listener);
}));
context.subscriptions.push(commands.registerCommand('nbls.node.properties.edit',
context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.node.properties.edit',
async (node) => await PropertiesView.createOrShow(context, node, (await client).findTreeViewService())));

context.subscriptions.push(commands.registerCommand(COMMAND_PREFIX + '.cloud.ocid.copy',
Expand Down Expand Up @@ -913,7 +913,7 @@ export function activate(context: ExtensionContext): VSNetBeansAPI {

const archiveFileProvider = <vscode.TextDocumentContentProvider> {
provideTextDocumentContent: async (uri: vscode.Uri, token: vscode.CancellationToken): Promise<string> => {
return await commands.executeCommand('nbls.get.archive.file.content', uri.toString());
return await commands.executeCommand(COMMAND_PREFIX + '.get.archive.file.content', uri.toString());
}
};
context.subscriptions.push(workspace.registerTextDocumentContentProvider('jar', archiveFileProvider));
Expand Down

0 comments on commit 5f47772

Please sign in to comment.