use jackson instead of gson - avoid loading extra lib, ensure that DefaultPackageServiceConfig is not created several times

GitOrigin-RevId: 65011d986c312ad50189758e31570480f1823991
This commit is contained in:
Vladimir Krivosheev
2022-01-11 15:43:33 +01:00
committed by intellij-monorepo-bot
parent d6f44b0194
commit 0f80de7516
17 changed files with 160 additions and 177 deletions

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.application.options;
import com.intellij.openapi.application.ApplicationManager;
@@ -7,6 +7,7 @@ import com.intellij.openapi.util.registry.RegistryValueListener;
import com.intellij.util.messages.Topic;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface RegistryManager {
@Topic.AppLevel
@@ -23,6 +24,8 @@ public interface RegistryManager {
int intValue(@NotNull String key);
@Nullable String stringValue(@NotNull String key);
int intValue(@NotNull String key, int defaultValue);
@NotNull

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.util
import com.intellij.openapi.Disposable
@@ -73,6 +73,7 @@ class SingleAlarm @JvmOverloads constructor(
else -> null
}
}
fun pooledThreadSingleAlarm(delay: Int, parentDisposable: Disposable, task: () -> Unit): SingleAlarm {
return SingleAlarm(Runnable(task), delay = delay, threadToUse = ThreadToUse.POOLED_THREAD, parentDisposable = parentDisposable)
}

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.openapi.util.registry
import com.intellij.application.options.RegistryManager
@@ -54,6 +54,8 @@ internal class RegistryManagerImpl : PersistentStateComponent<Element>, Registry
override fun intValue(key: String) = Registry._getWithoutStateCheck(key).asInteger()
override fun stringValue(key: String) = Registry._getWithoutStateCheck(key).asString()
override fun intValue(key: String, defaultValue: Int): Int {
return try {
Registry._getWithoutStateCheck(key).asInteger()

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.plugins.gradle.integrations.maven;
import com.intellij.CommonBundle;
@@ -33,7 +33,7 @@ import java.util.Set;
import static org.jetbrains.idea.maven.indices.MavenIndexUpdateManager.IndexUpdatingState.IDLE;
public class MavenRepositoriesHolder {
public final class MavenRepositoriesHolder {
private static final String UNINDEXED_MAVEN_REPOSITORIES_NOTIFICATION_GROUP = "Unindexed maven repositories gradle detection";
private static final Key<String> NOTIFICATION_KEY = Key.create(UNINDEXED_MAVEN_REPOSITORIES_NOTIFICATION_GROUP);
private final Project myProject;
@@ -88,7 +88,7 @@ public class MavenRepositoriesHolder {
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
List<MavenIndex> notIndexed =
ContainerUtil.filter(indicesManager.getIndex().getIndices(), index -> isNotIndexed(index.getRepositoryPathOrUrl()));
indicesManager.scheduleUpdateContent(notIndexed).onSuccess(aVoid -> {
indicesManager.scheduleUpdateContent(notIndexed).thenRun(() -> {
if (myNotIndexedUrls.isEmpty()) return;
for (MavenSearchIndex index : notIndexed) {
if (index.getUpdateTimestamp() != -1 || index.getFailureMessage() != null) {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.Disposable;
@@ -14,9 +14,6 @@ import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.concurrency.AsyncPromise;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.concurrency.Promises;
import org.jetbrains.idea.maven.project.MavenGeneralSettings;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.utils.MavenProcessCanceledException;
@@ -26,6 +23,7 @@ import org.jetbrains.idea.maven.utils.MavenRehighlighter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
/**
* Internal api class for update maven indices state.
@@ -33,17 +31,16 @@ import java.util.Objects;
* Contains logic for schedule async tasks for update index list or index.
*/
@ApiStatus.Internal
public class MavenIndexUpdateManager implements Disposable {
public final class MavenIndexUpdateManager implements Disposable {
private final Object myUpdatingIndicesLock = new Object();
private final List<String> myWaitingIndicesUrl = new ArrayList<>();
private final BackgroundTaskQueue myUpdatingQueue = new BackgroundTaskQueue(null, IndicesBundle.message("maven.indices.updating"));
private final MergingUpdateQueue myUpdateQueueList = new MergingUpdateQueue(
getClass().getName(), 1000, true, MergingUpdateQueue.ANY_COMPONENT, this, null, false
getClass().getName(), 1000, true, null, this, null, false
).usePassThroughInUnitTestMode();
private volatile String myCurrentUpdateIndexUrl;
Promise<Void> scheduleUpdateContent(@NotNull Project project, List<String> indicesUrl) {
CompletableFuture<?> scheduleUpdateContent(@NotNull Project project, List<String> indicesUrl) {
return scheduleUpdateContent(project, indicesUrl, true);
}
@@ -56,7 +53,9 @@ public class MavenIndexUpdateManager implements Disposable {
myUpdateQueueList.queue(Update.create(this, () -> {
MavenIndicesManager indicesManager = MavenIndicesManager.getInstance(project);
indicesManager.updateIndicesListSync();
if (project.isDisposed()) return;
if (project.isDisposed()) {
return;
}
MavenIndexHolder indexHolder = indicesManager.getIndex();
MavenIndex localIndex = indexHolder.getLocalIndex();
@@ -71,7 +70,7 @@ public class MavenIndexUpdateManager implements Disposable {
}));
}
Promise<Void> scheduleUpdateContent(@NotNull Project project, List<String> indicesUrls, final boolean fullUpdate) {
CompletableFuture<?> scheduleUpdateContent(@NotNull Project project, List<String> indicesUrls, final boolean fullUpdate) {
final List<String> toSchedule = new ArrayList<>();
synchronized (myUpdatingIndicesLock) {
@@ -83,10 +82,10 @@ public class MavenIndexUpdateManager implements Disposable {
myWaitingIndicesUrl.addAll(toSchedule);
}
if (toSchedule.isEmpty()) {
return Promises.resolvedPromise();
return CompletableFuture.completedFuture(null);
}
final AsyncPromise<Void> promise = new AsyncPromise<>();
final CompletableFuture<?> promise = new CompletableFuture<>();
myUpdatingQueue.run(new Task.Backgroundable(project, IndicesBundle.message("maven.indices.updating"), true) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
@@ -97,7 +96,7 @@ public class MavenIndexUpdateManager implements Disposable {
catch (MavenProcessCanceledException ignore) {
}
finally {
promise.setResult(null);
promise.complete(null);
}
}
});

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.Disposable;
@@ -7,6 +7,7 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.Pair;
import com.intellij.util.Consumer;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.io.PathKt;
import com.intellij.util.ui.update.MergingUpdateQueue;
@@ -14,7 +15,6 @@ import com.intellij.util.ui.update.Update;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.idea.maven.model.MavenArchetype;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.project.MavenProject;
@@ -34,6 +34,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import static org.jetbrains.idea.maven.indices.MavenArchetypeManager.loadUserArchetypes;
@@ -178,23 +179,24 @@ public final class MavenIndicesManager implements Disposable {
public void addArtifactIndexAsync(@Nullable MavenId mavenId, @NotNull File artifactFile) {
if (myMavenIndices.isNotInit()) return;
MavenIndex localIndex = myMavenIndices.getIndexHolder().getLocalIndex();
if (localIndex == null) return;
ApplicationManager.getApplication().executeOnPooledThread(() -> myIndexFixer.fixIndex(mavenId, artifactFile, localIndex));
if (localIndex == null) {
return;
}
AppExecutorUtil.getAppExecutorService().execute(() -> myIndexFixer.fixIndex(mavenId, artifactFile, localIndex));
}
/**
* Schedule update all indices content async.
*/
public void scheduleUpdateContentAll() {
myIndexUpdateManager
.scheduleUpdateContent(myProject, ContainerUtil.map(myMavenIndices.getIndices(), i -> i.getRepositoryPathOrUrl()));
myIndexUpdateManager.scheduleUpdateContent(myProject, ContainerUtil.map(myMavenIndices.getIndices(), MavenIndex::getRepositoryPathOrUrl));
}
/**
* Schedule update indices content async.
*/
public Promise<Void> scheduleUpdateContent(@NotNull List<MavenIndex> indices) {
return myIndexUpdateManager.scheduleUpdateContent(myProject, ContainerUtil.map(indices, i -> i.getRepositoryPathOrUrl()));
public CompletableFuture<?> scheduleUpdateContent(@NotNull List<MavenIndex> indices) {
return myIndexUpdateManager.scheduleUpdateContent(myProject, ContainerUtil.map(indices, MavenIndex::getRepositoryPathOrUrl));
}
/**

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.maven.onlinecompletion
import com.intellij.openapi.util.text.StringUtil
@@ -13,8 +13,7 @@ import java.util.function.Consumer
/**
* This class is used as a solution to support completion from repositories, which do not support online completion
*/
class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : DependencySearchProvider {
internal class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : DependencySearchProvider {
override fun fulltextSearch(searchString: String,
consumer: Consumer<RepositoryArtifactData>) {
val mavenId = MavenId(searchString)
@@ -29,7 +28,7 @@ class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : Dependency
private fun search(consumer: Consumer<RepositoryArtifactData>, mavenId: MavenId) {
for (groupId in myIndex.groupIds) {
if (groupId == null) continue;
if (groupId == null) continue
if (!mavenId.groupId.isNullOrEmpty() && !nonExactMatches(groupId, mavenId.groupId!!)) {
continue
}
@@ -37,7 +36,7 @@ class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : Dependency
if (!mavenId.artifactId.isNullOrEmpty() && !nonExactMatches(artifactId, mavenId.artifactId!!)) {
continue
}
if (artifactId == null) continue;
if (artifactId == null) continue
val info = MavenRepositoryArtifactInfo(groupId, artifactId, myIndex.getVersions(groupId, artifactId))
consumer.accept(info)
}
@@ -45,8 +44,8 @@ class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : Dependency
}
private fun nonExactMatches(template: String, real: String): Boolean {
val splittedTemplate = template.split(delimiters = *charArrayOf('-', '.'))
val splittedReal = real.split(delimiters = *charArrayOf('-', '.'))
val splittedTemplate = template.split(delimiters = charArrayOf('-', '.'))
val splittedReal = real.split(delimiters = charArrayOf('-', '.'))
if (splittedTemplate.size == 1 || splittedReal.size == 1) {
return StringUtil.startsWith(template, real) || StringUtil.startsWith(
real, template)
@@ -66,6 +65,4 @@ class IndexBasedCompletionProvider(private val myIndex: MavenIndex) : Dependency
val index: MavenSearchIndex
get() = myIndex
}

View File

@@ -9,17 +9,17 @@ import org.jetbrains.idea.reposearch.DependencySearchProvider;
import org.jetbrains.idea.reposearch.DependencySearchProvidersFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
public class MavenCompletionProviderFactory implements DependencySearchProvidersFactory {
@Override
public boolean isApplicable(Project project) {
return MavenIndicesManager.getInstance(project).isInit();
}
public @NotNull List<DependencySearchProvider> getProviders(@NotNull Project project) {
if (!MavenIndicesManager.getInstance(project).isInit()) {
return Collections.emptyList();
}
@Override
public @NotNull List<DependencySearchProvider> getProviders(Project project) {
List<DependencySearchProvider> result = new ArrayList<>();
result.add(new ProjectModulesCompletionProvider(project));

View File

@@ -60,8 +60,8 @@
<orderEntry type="module" module-name="intellij.gradle" />
<orderEntry type="module" module-name="intellij.maven" />
<orderEntry type="module" module-name="intellij.platform.analysis" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="library" name="kotlinx-serialization-core" level="project" />
<orderEntry type="library" name="kotlinx-serialization-json" level="project" />
<orderEntry type="module-library">
<library name="package-search-version-utils">
<CLASSES>
@@ -86,6 +86,5 @@
</orderEntry>
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
<orderEntry type="library" scope="TEST" name="JUnit5Params" level="project" />
<orderEntry type="library" name="commons-codec" level="project" />
</component>
</module>
</module>

View File

@@ -16,5 +16,7 @@
<orderEntry type="module" module-name="intellij.maven.model" exported="" />
<orderEntry type="library" name="gson" level="project" />
<orderEntry type="module" module-name="intellij.platform.ide.util.io" />
<orderEntry type="library" name="jackson-jr-objects" level="project" />
<orderEntry type="library" name="jackson" level="project" />
</component>
</module>

View File

@@ -1,101 +1,92 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.kpmsearch;
import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.fasterxml.jackson.jr.ob.JSON;
import com.intellij.application.options.RegistryManager;
import com.intellij.execution.process.ProcessIOExecutorService;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.Service;
import com.intellij.openapi.util.registry.Registry;
import com.intellij.util.concurrency.SameThreadExecutor;
import com.intellij.util.io.HttpRequests;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.concurrency.AsyncPromise;
import org.jetbrains.concurrency.Promise;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
@Service(Service.Level.APP)
public final class DefaultPackageServiceConfig implements PackageSearchEndpointConfig {
private static final Object MUTEX = new Object();
public final static long TIMEOUT = Registry.intValue("packagesearch.timeout");
private static final long INFO_TTL = TimeUnit.DAYS.toMillis(7);
private static final String CONFIG_URL_KEY_PREFIX = DefaultPackageServiceConfig.class.getSimpleName().toLowerCase(Locale.ENGLISH) + ".";
private static final String CONFIG_UPDATED_TIMESTAMP_KEY = CONFIG_URL_KEY_PREFIX + "updated.ts";
private volatile @NotNull PackageSearchEndpointUrls packageSearchEndpointUrls = new PackageSearchEndpointUrls(null, null);
private final static long INFO_TTL = TimeUnit.DAYS.toMillis(7);
private final static String CONFIG_URL = Registry.stringValue("packagesearch.config.url");
private final static String CONFIG_UPDATED_TIMESTAMP_KEY = "packagesearch.status.updated.ts";
private final static String CONFIG_URL_KEY_PREFIX = "packagesearch.endpoint.url.";
private static final Gson GSON = new Gson();
private volatile PackageSearchEndpointUrls myPackageSearchEndpointUrls;
public DefaultPackageServiceConfig() {
if (ApplicationManager.getApplication().isUnitTestMode() || !Registry.is("maven.packagesearch.enabled")) {
myPackageSearchEndpointUrls = null;
return;
private DefaultPackageServiceConfig() {
if (!ApplicationManager.getApplication().isUnitTestMode() && RegistryManager.getInstance().is("maven.packagesearch.enabled")) {
updateIfNecessary();
}
updateIfNessesary();
}
@SuppressWarnings("unchecked")
private Promise<PackageSearchEndpointUrls> reloadConfig() {
AsyncPromise<PackageSearchEndpointUrls> asyncPromise = new AsyncPromise<>();
asyncPromise.onError(t -> {});
ApplicationManager.getApplication().executeOnPooledThread(() -> {
private CompletableFuture<PackageSearchEndpointUrls> reloadConfig() {
return CompletableFuture.supplyAsync(() -> {
Map<String, Object> config;
try {
LinkedTreeMap config = GSON.fromJson(
HttpRequests.request(CONFIG_URL)
.userAgent(getUserAgent())
.forceHttps(true)
.readString(), LinkedTreeMap.class);
Object idea = config.get("idea");
if (!(idea instanceof Map)) {
asyncPromise.setResult(new PackageSearchEndpointUrls(null, null));
return;
}
config = HttpRequests.request(Objects.requireNonNull(RegistryManager.getInstance().stringValue("packagesearch.config.url")))
.userAgent(getUserAgent())
.forceHttps(true)
.connect(request -> JSON.std.mapFrom(request.getReader()));
}
catch (IOException e) {
throw new UncheckedIOException(e);
}
Object idea = config.get("idea");
if (!(idea instanceof Map)) {
return new PackageSearchEndpointUrls(null, null);
}
String fulltextUrl = extract("fulltext", (Map<Object, Object>)idea);
String suggestUrl = extract("suggest", (Map<Object, Object>)idea);
asyncPromise.setResult(new PackageSearchEndpointUrls(fulltextUrl, suggestUrl));
}
catch (Exception e) {
asyncPromise.setError(e);
}
});
return asyncPromise;
@SuppressWarnings("unchecked")
Map<String, Object> o = (Map<String, Object>)idea;
String fulltextUrl = extract("fulltext", o);
String suggestUrl = extract("suggest", o);
return new PackageSearchEndpointUrls(fulltextUrl, suggestUrl);
}, ApplicationManager.getApplication().isDispatchThread() ? ProcessIOExecutorService.INSTANCE : SameThreadExecutor.INSTANCE);
}
@Override
public String getFullTextUrl() {
if (myPackageSearchEndpointUrls == null){
return null;
}
return myPackageSearchEndpointUrls.fulltextUrl;
return packageSearchEndpointUrls.fulltextUrl;
}
@Override
public String getSuggestUrl() {
if (myPackageSearchEndpointUrls == null){
return null;
}
return myPackageSearchEndpointUrls.suggestUrl;
return packageSearchEndpointUrls.suggestUrl;
}
@Override
public int getReadTimeout() {
return (int)TIMEOUT;
return Registry.intValue("packagesearch.timeout");
}
@Override
public int getConnectTimeout() {
return (int)TIMEOUT;
return getReadTimeout();
}
private static String extract(String fulltext, Map<Object, Object> idea) {
private static String extract(String fulltext, Map<String, Object> idea) {
Object urlMap = idea.get(fulltext);
if (urlMap instanceof Map) {
Object enabled = ((Map<?, ?>)urlMap).get("enabled");
if (Boolean.valueOf(String.valueOf(enabled))) {
Object url = ((Map<?, ?>)urlMap).get("url");
//noinspection unchecked
if (Boolean.valueOf(String.valueOf(((Map<String, Object>)urlMap).get("enabled")))) {
@SuppressWarnings("unchecked")
Object url = ((Map<String, ?>)urlMap).get("url");
if (url instanceof String) {
return url.toString();
}
@@ -104,38 +95,30 @@ public final class DefaultPackageServiceConfig implements PackageSearchEndpointC
return null;
}
private void updateIfNessesary() {
synchronized (MUTEX) {
long updatedTimestamp = PropertiesComponent.getInstance().getLong(CONFIG_UPDATED_TIMESTAMP_KEY, 0);
if (System.currentTimeMillis() - updatedTimestamp > INFO_TTL) {
reloadConfig().onSuccess(eu -> {
PropertiesComponent.getInstance().setValue(CONFIG_UPDATED_TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
PropertiesComponent.getInstance().setValue(CONFIG_URL_KEY_PREFIX + "fulltext", eu.fulltextUrl);
PropertiesComponent.getInstance().setValue(CONFIG_URL_KEY_PREFIX + "suggest", eu.suggestUrl);
myPackageSearchEndpointUrls = eu;
myPackageSearchEndpointUrls = loadPersistedResult();
});
}
else {
myPackageSearchEndpointUrls = loadPersistedResult();
}
private void updateIfNecessary() {
PropertiesComponent persistentCache = PropertiesComponent.getInstance();
long updatedTimestamp = persistentCache.getLong(CONFIG_UPDATED_TIMESTAMP_KEY, 0);
if ((System.currentTimeMillis() - updatedTimestamp) > INFO_TTL) {
reloadConfig().thenAccept(result -> {
persistentCache.setValue(CONFIG_UPDATED_TIMESTAMP_KEY, String.valueOf(System.currentTimeMillis()));
persistentCache.setValue(CONFIG_URL_KEY_PREFIX + "fulltext", result.fulltextUrl);
persistentCache.setValue(CONFIG_URL_KEY_PREFIX + "suggest", result.suggestUrl);
packageSearchEndpointUrls = result;
});
}
else {
packageSearchEndpointUrls = new PackageSearchEndpointUrls(
persistentCache.getValue(CONFIG_URL_KEY_PREFIX + "fulltext"),
persistentCache.getValue(CONFIG_URL_KEY_PREFIX + "suggest")
);
}
}
@NotNull
private static PackageSearchEndpointUrls loadPersistedResult() {
return new PackageSearchEndpointUrls(
PropertiesComponent.getInstance().getValue(CONFIG_URL_KEY_PREFIX + "fulltext"),
PropertiesComponent.getInstance().getValue(CONFIG_URL_KEY_PREFIX + "suggest"));
}
static class PackageSearchEndpointUrls {
static final class PackageSearchEndpointUrls {
final String fulltextUrl;
final String suggestUrl;
PackageSearchEndpointUrls(String fulltextUrl, String suggestUrl) {
PackageSearchEndpointUrls(@Nullable String fulltextUrl, @Nullable String suggestUrl) {
this.fulltextUrl = fulltextUrl;
this.suggestUrl = suggestUrl;
}

View File

@@ -1,7 +1,8 @@
package org.jetbrains.idea.kpmsearch;
import com.intellij.application.options.RegistryManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.registry.Registry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.reposearch.DependencySearchProvider;
import org.jetbrains.idea.reposearch.DependencySearchProvidersFactory;
@@ -10,12 +11,10 @@ import java.util.Collections;
final class KpmSearchFactoryProvider implements DependencySearchProvidersFactory {
@Override
public boolean isApplicable(Project project) {
return Registry.is("maven.packagesearch.enabled");
}
@Override
public Collection<DependencySearchProvider> getProviders(Project project) {
public Collection<DependencySearchProvider> getProviders(@NotNull Project project) {
if (!RegistryManager.getInstance().is("maven.packagesearch.enabled")) {
return Collections.emptyList();
}
return Collections.singleton(new PackageSearchService());
}
}

View File

@@ -6,14 +6,11 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public interface PackageSearchEndpointConfig {
@Nullable
String getFullTextUrl();
@Nullable String getFullTextUrl();
@Nullable
String getSuggestUrl();
@Nullable String getSuggestUrl();
@NotNull
default String getUserAgent() {
default @NotNull String getUserAgent() {
return ApplicationNamesInfo.getInstance().getProductName() + "/" + ApplicationInfo.getInstance().getFullVersion();
}

View File

@@ -3,6 +3,7 @@ package org.jetbrains.idea.kpmsearch;
import com.google.gson.Gson;
import com.google.gson.stream.JsonReader;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.util.text.Strings;
@@ -23,25 +24,29 @@ import java.util.Set;
import java.util.function.Consumer;
public final class PackageSearchService implements DependencySearchProvider {
private final PackageSearchEndpointConfig myPackageServiceConfig;
private final PackageSearchEndpointConfig packageServiceConfig;
public PackageSearchService() {
this(new DefaultPackageServiceConfig());
packageServiceConfig = ApplicationManager.getApplication().getService(DefaultPackageServiceConfig.class);
}
public PackageSearchService(PackageSearchEndpointConfig config) {
myPackageServiceConfig = config;
packageServiceConfig = config;
}
@Override
public void fulltextSearch(@NotNull String searchString, @NotNull Consumer<RepositoryArtifactData> consumer) {
searchString = normalize(searchString);
ProgressManager.checkCanceled();
doRequest(consumer, createUrlFullTextSearch(searchString));
if (searchString != null) {
doRequest(consumer, createUrlFullTextSearch(searchString));
}
}
private static String normalize(@Nullable String string) {
if (StringUtil.isEmpty(string)) return null;
private static @Nullable String normalize(@Nullable String string) {
if (Strings.isEmpty(string)) {
return null;
}
StringBuilder builder = new StringBuilder();
for (char c : string.toCharArray()) {
if (isAcceptable(c)) {
@@ -78,10 +83,10 @@ public final class PackageSearchService implements DependencySearchProvider {
try {
HttpRequests.request(url)
.userAgent(myPackageServiceConfig.getUserAgent())
.forceHttps(myPackageServiceConfig.forceHttps())
.connectTimeout(myPackageServiceConfig.getReadTimeout())
.readTimeout(myPackageServiceConfig.getConnectTimeout())
.userAgent(packageServiceConfig.getUserAgent())
.forceHttps(packageServiceConfig.forceHttps())
.connectTimeout(packageServiceConfig.getReadTimeout())
.readTimeout(packageServiceConfig.getConnectTimeout())
.connect(request -> process(consumer, request));
}
catch (IOException ignore) {
@@ -109,35 +114,38 @@ public final class PackageSearchService implements DependencySearchProvider {
}
private String createUrlFullTextSearch(@NotNull String coord) {
String url = myPackageServiceConfig.getFullTextUrl();
if (StringUtil.isEmpty(url)) {
String url = packageServiceConfig.getFullTextUrl();
if (Strings.isEmpty(url)) {
return null;
}
if (StringUtil.isEmpty(coord)) {
else if (Strings.isEmpty(coord)) {
return url;
}
return url + "?query=" + encode(coord.trim());
else {
return url + "?query=" + encode(coord.trim());
}
}
private String createUrlSuggestPrefix(@Nullable String groupId, @Nullable String artifactId) {
String url = myPackageServiceConfig.getSuggestUrl();
if (StringUtil.isEmpty(url)) {
String url = packageServiceConfig.getSuggestUrl();
if (Strings.isEmpty(url)) {
return null;
}
String groupParam = StringUtil.isEmpty(groupId) ? "" : "groupId=" + encode(groupId.trim());
String artifactParam = StringUtil.isEmpty(artifactId) ? "" : "artifactId=" + encode(artifactId.trim());
String groupParam = Strings.isEmpty(groupId) ? "" : "groupId=" + encode(groupId.trim());
String artifactParam = Strings.isEmpty(artifactId) ? "" : "artifactId=" + encode(artifactId.trim());
final StringBuilder sb = new StringBuilder(url);
if (StringUtil.isNotEmpty(groupParam)) {
if (Strings.isNotEmpty(groupParam)) {
sb.append('?');
sb.append(groupParam);
if (StringUtil.isNotEmpty(artifactParam)) sb.append('&');
if (Strings.isNotEmpty(artifactParam)) sb.append('&');
}
if (StringUtil.isNotEmpty(artifactParam)) {
if (StringUtil.isEmpty(groupParam)) sb.append('?');
if (Strings.isNotEmpty(artifactParam)) {
if (Strings.isEmpty(groupParam)) {
sb.append('?');
}
sb.append(artifactParam);
}

View File

@@ -6,15 +6,11 @@ import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
@ApiStatus.Experimental
public interface DependencySearchProvider {
void fulltextSearch(@NotNull String searchString, @NotNull Consumer<RepositoryArtifactData> consumer);
void fulltextSearch(@NotNull String searchString,
@NotNull Consumer<RepositoryArtifactData> consumer);
void suggestPrefix(@Nullable String groupId, @Nullable String artifactId,
@NotNull Consumer<RepositoryArtifactData> consumer);
void suggestPrefix(@Nullable String groupId, @Nullable String artifactId, @NotNull Consumer<RepositoryArtifactData> consumer);
boolean isLocal();
}

View File

@@ -2,12 +2,11 @@ package org.jetbrains.idea.reposearch;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
@ApiStatus.Experimental
public interface DependencySearchProvidersFactory {
boolean isApplicable(Project project);
Collection<DependencySearchProvider> getProviders(Project project);
Collection<DependencySearchProvider> getProviders(@NotNull Project project);
}

View File

@@ -64,10 +64,6 @@ class DependencySearchService(private val project: Project) : Disposable {
if (project.isDisposed) return
for (f in EP_NAME.extensionList) {
if (!f.isApplicable(project)) {
continue
}
for (provider in f.getProviders(project)) {
if (provider.isLocal) {
newLocalProviders.add(provider)