Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

fix: don't leak deployment jar classes #1078

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ public MicroProfileProjectInfo getMicroProfileProjectInfo(Module module,
.collect(Collectors.joining("+")) //
+ "'");
long startTime = System.currentTimeMillis();
boolean excludeTestCode = classpathKind == ClasspathKind.SRC;
PropertiesCollector collector = new PropertiesCollector(info, scopes);
if (module != null) {
SearchScope scope = createSearchScope(module, scopes, classpathKind == ClasspathKind.TEST);
Expand Down Expand Up @@ -153,17 +152,17 @@ private static MicroProfileProjectInfo createInfo(Module module, ClasspathKind c
return info;
}

private SearchScope createSearchScope(Module module, List<MicroProfilePropertiesScope> scopes,
private SearchScope createSearchScope(@NotNull Module module, List<MicroProfilePropertiesScope> scopes,
boolean excludeTestCode) {
SearchScope searchScope = GlobalSearchScope.EMPTY_SCOPE;
SearchScope searchScope = GlobalSearchScope.moduleRuntimeScope(module, !excludeTestCode);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

allows finding properties in RUNTIME scope


for (MicroProfilePropertiesScope scope : scopes) {
switch (scope) {
case sources:
searchScope = module != null ? searchScope.union(module.getModuleScope(!excludeTestCode)) : searchScope;
searchScope = searchScope.union(module.getModuleScope(!excludeTestCode));
break;
case dependencies:
searchScope = module != null ? searchScope.union(module.getModuleWithLibrariesScope()) : searchScope;
searchScope = searchScope.union(module.getModuleWithLibrariesScope());
break;
/*added missing default case */
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,7 @@ public Integer getPropertyAsInteger(String key, Integer defaultValue) {
return defaultValue;
}
try {
int intValue = Integer.parseInt(value);
return intValue;
return Integer.parseInt(value);
} catch (NumberFormatException nfe) {
return defaultValue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,14 @@ public class QuarkusModuleUtil {
public static final Pattern APPLICATION_YAML = Pattern.compile("application(-.+)?\\.ya?ml");

public static boolean isQuarkusExtensionWithDeploymentArtifact(Library library) {
boolean result = false;
if (library != null) {
VirtualFile[] files = library.getFiles(OrderRootType.CLASSES);

for(int i=0; !result && i < files.length;++i) {
if (files[i].isDirectory()) {
result = ToolDelegate.getDeploymentJarId(VfsUtilCore.virtualToIoFile(files[i])) != null;
for(VirtualFile vFile : library.getFiles(OrderRootType.CLASSES)) {
if (vFile.isDirectory() && ToolDelegate.hasExtensionProperties(VfsUtilCore.virtualToIoFile(vFile))) {
return true;
}
}
}
return result;
return false;
}

/**
Expand All @@ -81,7 +78,7 @@ public static void ensureQuarkusLibrary(Module module, ProgressIndicator progres
long start = System.currentTimeMillis();
ToolDelegate toolDelegate = ToolDelegate.getDelegate(module);
if (toolDelegate != null) {
LOGGER.info("Tool delegate found for " + module.getName());
LOGGER.info(toolDelegate.getDisplay() + " tool delegate found for " + module.getName());
if (isQuarkusModule(module)) {
LOGGER.info("isQuarkus module " + module.getName());
QuarkusModuleComponent component = module.getComponent(QuarkusModuleComponent.class);
Expand Down Expand Up @@ -126,14 +123,15 @@ private static void addLibrary(ModifiableRootModel model, List<VirtualFile>[] fi

LibraryOrderEntry entry = model.findLibraryOrderEntry(library);
assert entry != null : library;
entry.setScope(DependencyScope.PROVIDED);
entry.setScope(DependencyScope.RUNTIME);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

avoid deployment jars to leak classes in compile scope

entry.setExported(false);
ApplicationManager.getApplication().invokeAndWait(() -> {
WriteAction.run(libraryModel::commit);
});
}

private static Integer computeHash(Module module) {
long start = System.currentTimeMillis();
ModuleRootManager manager = ModuleRootManager.getInstance(module);
Set<String> files = manager.processOrder(new RootPolicy<Set<String>>() {
@Override
Expand All @@ -146,6 +144,8 @@ public Set<String> visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrde
return value;
}
}, new HashSet<>());
long elapsed = System.currentTimeMillis() - start;
System.out.println("computeHash for "+module.getName()+" took "+elapsed+"ms");
return files.isEmpty()?null:files.hashCode();
}

Expand All @@ -162,20 +162,18 @@ public static boolean isQuarkusModule(Module module) {
return libraries.process(new RootPolicy<Boolean>() {
@Override
public Boolean visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEntry, Boolean value) {
return value | isQuarkusLibrary(libraryOrderEntry);
return value || isQuarkusLibrary(libraryOrderEntry);
}
}, false);
}

public static boolean isQuarkusLibrary(@NotNull LibraryOrderEntry libraryOrderEntry) {
return libraryOrderEntry != null &&
libraryOrderEntry.getLibraryName() != null &&
return libraryOrderEntry.getLibraryName() != null &&
libraryOrderEntry.getLibraryName().contains("io.quarkus:quarkus-core:");
}

public static boolean isQuarkusDeploymentLibrary(@NotNull LibraryOrderEntry libraryOrderEntry) {
return libraryOrderEntry != null &&
libraryOrderEntry.getLibraryName() != null &&
return libraryOrderEntry.getLibraryName() != null &&
libraryOrderEntry.getLibraryName().equalsIgnoreCase(QuarkusConstants.QUARKUS_DEPLOYMENT_LIBRARY_NAME);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,6 @@ public QuarkusProjectService(Project project) {
connection = project.getMessageBus().connect();
connection.subscribe(ClasspathResourceChangedManager.TOPIC, this);
connection.subscribe(ProjectTopics.MODULES, this);
// Add the Quarkus deployment preprocessor
ClasspathResourceChangedManager.getInstance(project)
.addPreprocessor(
(progressIndicator) -> {
processModules(progressIndicator);
});
}

@Override
public void moduleAdded(@NotNull Project project, @NotNull Module module) {
QuarkusModuleUtil.ensureQuarkusLibrary(module, new EmptyProgressIndicator());
}

public VirtualFile getSchema(Module module) {
Expand Down Expand Up @@ -138,10 +127,10 @@ public void sourceFilesChanged(Set<com.intellij.openapi.util.Pair<VirtualFile, M
}

public void processModules(com.intellij.openapi.progress.ProgressIndicator progressIndicator) {
for (var module : ModuleManager.getInstance(project).getModules()) {
LOGGER.info("Calling ensure from processModules");
QuarkusModuleUtil.ensureQuarkusLibrary(module, progressIndicator);
}
// for (var module : ModuleManager.getInstance(project).getModules()) {
// LOGGER.info("Calling ensure from processModules");
// QuarkusModuleUtil.ensureQuarkusLibrary(module, progressIndicator);
// }
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
******************************************************************************/
package com.redhat.devtools.intellij.quarkus.lang;

import com.intellij.codeInspection.unused.ImplicitPropertyUsageProvider;
import com.intellij.lang.properties.codeInspection.unused.ImplicitPropertyUsageProvider;
import com.intellij.lang.properties.psi.Property;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;

public class QuarkusImplicitPropertyUsageProvider extends ImplicitPropertyUsageProvider {
public class QuarkusImplicitPropertyUsageProvider implements ImplicitPropertyUsageProvider {
@Override
public boolean isUsed(Property property) {
return QuarkusModuleUtil.isQuarkusPropertiesFile(property.getContainingFile().getVirtualFile(), property.getProject());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@
package com.redhat.devtools.intellij.quarkus.lsp;

import com.intellij.openapi.module.Module;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.messages.MessageBusConnection;
import com.redhat.devtools.intellij.lsp4ij.client.IndexAwareLanguageClient;
import com.redhat.devtools.intellij.lsp4mp4ij.classpath.ClasspathResourceChangedManager;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.ProjectLabelManager;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.PropertiesManager;
import com.redhat.devtools.intellij.lsp4mp4ij.psi.core.PropertiesManagerForJava;
Expand All @@ -23,15 +29,15 @@
import com.redhat.devtools.intellij.lsp4mp4ij.psi.internal.core.ls.PsiUtilsLSImpl;
import com.redhat.devtools.intellij.lsp4mp4ij.settings.UserDefinedMicroProfileSettings;
import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil;
import com.redhat.devtools.intellij.lsp4ij.client.IndexAwareLanguageClient;
import com.redhat.devtools.intellij.lsp4mp4ij.classpath.ClasspathResourceChangedManager;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4mp.commons.*;
import org.eclipse.lsp4mp.commons.codeaction.CodeActionResolveData;
import org.eclipse.lsp4mp.commons.utils.JSONUtility;
import org.eclipse.lsp4mp.ls.api.MicroProfileLanguageClientAPI;
import org.eclipse.lsp4mp.ls.api.MicroProfileLanguageServerAPI;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.Set;
Expand Down Expand Up @@ -91,7 +97,7 @@ public void sourceFilesChanged(Set<Pair<VirtualFile, Module>> sources) {
List<Pair<String, MicroProfilePropertiesScope>> info = sources.stream()
.filter(pair -> isJavaFile(pair.getFirst()) || isConfigSource(pair.getFirst()))
.map(pair -> Pair.pair(PsiUtilsLSImpl.getProjectURI(pair.getSecond()), getScope(pair.getFirst()))).
collect(Collectors.toList());
collect(Collectors.toList());
if (!info.isEmpty()) {
sendPropertiesChangeEvent(info.stream().map(p -> p.getSecond()).collect(Collectors.toList()),
info.stream().map(p -> p.getFirst()).collect(Collectors.toSet()));
Expand All @@ -112,10 +118,38 @@ private boolean isConfigSource(VirtualFile file) {

@Override
public CompletableFuture<MicroProfileProjectInfo> getProjectInfo(MicroProfileProjectInfoParams params) {
String filePath = getFilePath(params.getUri());
return runAsBackground("Computing MicroProfile properties for '" + filePath + "'.", monitor ->
PropertiesManager.getInstance().getMicroProfileProjectInfo(params, PsiUtilsLSImpl.getInstance(getProject()), monitor)
);
CompletableFuture<Boolean> future = new CompletableFuture<>();
CompletableFuture.runAsync(() -> {
Runnable task = () -> ProgressManager.getInstance().run(new Task.Backgroundable(getProject(), "Computing deployment jars...") {
@Override
public void run(@NotNull ProgressIndicator indicator) {
System.out.println("Computing deployment jars...");
IPsiUtils utils = PsiUtilsLSImpl.getInstance(getProject());
try {
VirtualFile file = utils.findFile(params.getUri());
Module module = utils.getModule(file);
long start = System.currentTimeMillis();
QuarkusModuleUtil.ensureQuarkusLibrary(module, indicator);
long elapsed = System.currentTimeMillis() - start;
System.out.println("Ensured QuarkusLibrary in "+ elapsed+ " ms");
future.complete(true);
} catch (Exception e) {
future.completeExceptionally(e);
}
}
});
if (DumbService.getInstance(getProject()).isDumb()) {
DumbService.getInstance(getProject()).runWhenSmart(task);
} else {
task.run();
}
});
return future.thenCompose(Boolean -> {
String filePath = getFilePath(params.getUri());
return runAsBackground("Computing MicroProfile properties for '" + filePath + "'.", monitor ->
PropertiesManager.getInstance().getMicroProfileProjectInfo(params, PsiUtilsLSImpl.getInstance(getProject()), monitor)
);
});
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,17 +162,22 @@ private List<MavenArtifact> ensureDownloaded(Module module, MavenProject mavenPr
long start = System.currentTimeMillis();
try {
MavenEmbedderWrapper serverWrapper = createEmbedderWrapper(module.getProject(), mavenProject.getDirectory());
if (serverWrapper == null) {
return Collections.emptyList();
}
if (classifier != null) {
for(MavenId id : deploymentIds) {
result.add(serverWrapper.resolve(new MavenArtifactInfo(id, "jar", classifier), mavenProject.getRemoteRepositories()));
}
} else {
List<MavenArtifactInfo> infos = deploymentIds.stream().map(id -> new MavenArtifactInfo(id, "jar", classifier)).collect(Collectors.toList());
result = serverWrapper.resolveTransitively(infos, mavenProject.getRemoteRepositories());
result = serverWrapper.resolveArtifactTransitively(infos, mavenProject.getRemoteRepositories()).mavenResolvedArtifacts;
}
} catch (MavenProcessCanceledException | RuntimeException e) {
LOGGER.warn(e.getLocalizedMessage(), e);
}
long elapsed = System.currentTimeMillis() - start;
System.out.println("ensureDownloaded took "+elapsed+ "ms");
return result;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,38 +25,57 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import java.util.*;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

import static com.redhat.devtools.intellij.quarkus.QuarkusConstants.QUARKUS_DEPLOYMENT_PROPERTY_NAME;
import static com.redhat.devtools.intellij.quarkus.QuarkusConstants.QUARKUS_EXTENSION_PROPERTIES;

public interface ToolDelegate {

Map<String, String> DEPLOYMENTS = new HashMap<>();
String NO_DEPLOYMENTS = "NO_DEPLOYMENT";

static String getDeploymentJarId(File file) {
String result = null;
long start = System.currentTimeMillis();
String extensionId = null;
if (file.isDirectory()) {
File quarkusFile = new File(file, QUARKUS_EXTENSION_PROPERTIES);
if (quarkusFile.exists()) {
try (Reader r = new FileReader(quarkusFile)) {
result = getQuarkusExtension(r);
extensionId = getQuarkusExtension(r);
} catch (IOException e) {}
}
} else {
try {
JarFile jarFile = new JarFile(file);
String path = file.getAbsolutePath();
String cachedValue = DEPLOYMENTS.get(path);
if (NO_DEPLOYMENTS.equals(cachedValue)) {
return null;
}
if (cachedValue != null) {
return cachedValue;
}
//Not cached yet, look into the jar
try (JarFile jarFile = new JarFile(file)){
JarEntry entry = jarFile.getJarEntry(QUARKUS_EXTENSION_PROPERTIES);
if (entry != null) {
try (Reader r = new InputStreamReader(jarFile.getInputStream(entry),"UTF-8")) {
result = getQuarkusExtension(r);
extensionId = getQuarkusExtension(r);
}
}
} catch (IOException e) {}
} catch (IOException ignored) {}

DEPLOYMENTS.put(path, (extensionId == null)?NO_DEPLOYMENTS:extensionId);

}
return result;
long elapsed = System.currentTimeMillis() - start;
//System.out.println("getDeploymentJarId for "+file.getName()+" took "+ elapsed +" ms");
return extensionId;
}

static boolean hasExtensionProperties(File file) {
return getDeploymentJarId(file) != null;
}

static String getQuarkusExtension(Reader r) throws IOException {
Expand Down
Loading