Skip to content

Commit 4aeb2be

Browse files
authoredNov 5, 2024··
Merge pull request #7905 from apache/delivery
Sync delivery to release240 for 24-rc2
2 parents 4d10c98 + f640500 commit 4aeb2be

File tree

11 files changed

+383
-31
lines changed

11 files changed

+383
-31
lines changed
 

‎.github/workflows/main.yml

+15-1
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,25 @@ jobs:
416416
- name: Build nbms
417417
run: ant $OPTS build-nbms
418418

419-
# 13-14 min
419+
# 13-14 min for javadoc; JDK version must be synced with nb-javac
420+
- name: Set up JDK 23 for javadoc
421+
if: env.test_javadoc == 'true' && success()
422+
uses: actions/setup-java@v4
423+
with:
424+
java-version: 23
425+
distribution: ${{ env.DEFAULT_JAVA_DISTRIBUTION }}
426+
420427
- name: Build javadoc
421428
if: env.test_javadoc == 'true' && success()
422429
run: ant $OPTS build-javadoc
423430

431+
- name: Set up JDK ${{ matrix.java }}
432+
if: env.test_javadoc == 'true' && success()
433+
uses: actions/setup-java@v4
434+
with:
435+
java-version: ${{ matrix.java }}
436+
distribution: ${{ env.DEFAULT_JAVA_DISTRIBUTION }}
437+
424438
# runs only in PRs if requested; ~18 min
425439
- name: Build all Tests
426440
if: env.test_tests == 'true' && github.event_name == 'pull_request' && success()

‎enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/ConfigMapProvider.java

+3-12
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ public String getMicronautConfigFiles() {
6464

6565
public void createConfigMap() {
6666
KubernetesUtils.runWithClient(cluster, client -> {
67-
boolean configMapExist = checkIfConfigMapExist(client);
68-
if (configMapExist) {
67+
ConfigMapList cmList = client.configMaps().inNamespace(cluster.getNamespace()).list();
68+
ConfigMap configMap = (ConfigMap) KubernetesUtils.findResource(client, cmList, projectName);
69+
if (configMap != null) {
6970
updateConfigMap(client);
7071
return;
7172
}
@@ -87,16 +88,6 @@ public ConfigMapVolumeSource getVolumeSource() {
8788
.build();
8889
}
8990

90-
private boolean checkIfConfigMapExist(KubernetesClient client) {
91-
ConfigMapList cmList = client.configMaps().inNamespace(cluster.getNamespace()).list();
92-
for (ConfigMap cm : cmList.getItems()) {
93-
if (projectName.equals(cm.getMetadata().getName())) {
94-
return true;
95-
}
96-
}
97-
return false;
98-
}
99-
10091
private void updateConfigMap(KubernetesClient client) {
10192
Map<String, String> applicationProperties = propertiesGenerator.getApplication();
10293
Map<String, String> bootstrapProperties = propertiesGenerator.getBootstrap();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,303 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.netbeans.modules.cloud.oracle.assets;
20+
21+
import io.fabric8.kubernetes.api.model.PodTemplateSpec;
22+
import io.fabric8.kubernetes.api.model.PodTemplateSpecBuilder;
23+
import io.fabric8.kubernetes.api.model.Secret;
24+
import io.fabric8.kubernetes.api.model.SecretList;
25+
import io.fabric8.kubernetes.api.model.ServiceAccount;
26+
import io.fabric8.kubernetes.api.model.ServiceAccountBuilder;
27+
import io.fabric8.kubernetes.api.model.ServiceAccountList;
28+
import java.util.Arrays;
29+
import java.util.Collections;
30+
import java.util.HashSet;
31+
import java.util.List;
32+
import java.util.Set;
33+
import java.util.concurrent.CompletableFuture;
34+
import org.netbeans.spi.lsp.CommandProvider;
35+
import org.openide.util.lookup.ServiceProvider;
36+
import io.fabric8.kubernetes.api.model.batch.v1.CronJobList;
37+
import io.fabric8.kubernetes.api.model.batch.v1.CronJob;
38+
import io.fabric8.kubernetes.api.model.batch.v1.CronJobBuilder;
39+
import io.fabric8.kubernetes.api.model.batch.v1.JobBuilder;
40+
import io.fabric8.kubernetes.api.model.rbac.ClusterRole;
41+
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding;
42+
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingBuilder;
43+
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBindingList;
44+
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBuilder;
45+
import io.fabric8.kubernetes.api.model.rbac.ClusterRoleList;
46+
import io.fabric8.kubernetes.client.KubernetesClient;
47+
import java.util.Calendar;
48+
import java.util.UUID;
49+
import java.util.concurrent.Executors;
50+
import java.util.concurrent.ScheduledExecutorService;
51+
import java.util.concurrent.ScheduledFuture;
52+
import java.util.concurrent.TimeUnit;
53+
import java.util.concurrent.TimeoutException;
54+
import java.util.function.Supplier;
55+
import org.netbeans.modules.cloud.oracle.NotificationUtils;
56+
import org.netbeans.modules.cloud.oracle.compute.ClusterItem;
57+
import org.openide.util.NbBundle;
58+
59+
/**
60+
*
61+
* @author Dusan Petrovic
62+
*/
63+
@NbBundle.Messages({
64+
"CronJobCreationError=Error while creating secret rotation CronJob"
65+
})
66+
@ServiceProvider(service = CommandProvider.class)
67+
public class CreateSecretRotationCronJobCommand implements CommandProvider {
68+
69+
private static final String COMMAND_CREATE_CRONJOB = "nbls.cloud.assets.cluster.cronjob.create"; //NOI18N
70+
private static final String SECRET_NAME = "docker-bearer-vscode-generated-ocirsecret"; //NOI18N
71+
private static final String CRONJOB_NAME = "secret-rotation-cronjob"; //NOI18N
72+
private static final String CLUSTER_ROLE_BINDING_NAME = "secret-manager-binding"; //NOI18N
73+
private static final String CLUSTER_ROLE_NAME = "secret-manager"; //NOI18N
74+
private static final String SERVICE_ACCOUNT_NAME = "create-secret-svc-account"; //NOI18N
75+
private static final String BASE_IMAGE = "ghcr.io/oracle/oci-cli:latest"; //NOI18N
76+
private static final String CONTAINER_NAME = "create-secret"; //NOI18N
77+
private static final int WAITING_TIMEOUT = 60;
78+
79+
private static final Set COMMANDS = new HashSet<>(Arrays.asList(
80+
COMMAND_CREATE_CRONJOB
81+
));
82+
83+
private ClusterItem cluster;
84+
85+
@Override
86+
public Set<String> getCommands() {
87+
return Collections.unmodifiableSet(COMMANDS);
88+
}
89+
90+
@Override
91+
public CompletableFuture<Object> runCommand(String command, List<Object> arguments) {
92+
return createSecretRotationCronJob();
93+
}
94+
95+
public CompletableFuture<Object> createSecretRotationCronJob() {
96+
CompletableFuture completableFuture = new CompletableFuture();
97+
this.cluster = CloudAssets.getDefault().getItem(ClusterItem.class);
98+
KubernetesUtils.runWithClient(cluster, client -> {
99+
try {
100+
ServiceAccount serviceAccount = createServiceAccountIfNotExist(client);
101+
createClusterRoleIfNotExist(client);
102+
createClusterRoleBindingIfNotExist(client);
103+
createCronJobIfNotExist(client, serviceAccount);
104+
completableFuture.complete(null);
105+
} catch(Exception ex) {
106+
completableFuture.completeExceptionally(ex);
107+
NotificationUtils.showErrorMessage(Bundle.CronJobCreationError());
108+
}
109+
});
110+
return completableFuture;
111+
}
112+
113+
private void createCronJobIfNotExist(KubernetesClient client, ServiceAccount serviceAccount) {
114+
CronJobList existingCronJobs = client.batch().v1().cronjobs().inNamespace(cluster.getNamespace()).list();
115+
CronJob cronJob = (CronJob) KubernetesUtils.findResource(client, existingCronJobs, CRONJOB_NAME);
116+
if (cronJob != null) {
117+
if (!secretExist(client)) {
118+
invokeCronJob(client, cronJob);
119+
}
120+
return;
121+
}
122+
cronJob = new CronJobBuilder()
123+
.withNewMetadata()
124+
.withName(CRONJOB_NAME)
125+
.withNamespace(cluster.getNamespace())
126+
.endMetadata()
127+
.withNewSpec()
128+
.withSchedule(getCronExpression())
129+
.withNewJobTemplate()
130+
.withNewSpec()
131+
.withBackoffLimit(0)
132+
.withTemplate(cronJobPodTemplate(serviceAccount))
133+
.endSpec()
134+
.endJobTemplate()
135+
.endSpec()
136+
.build();
137+
138+
client.batch().v1()
139+
.cronjobs()
140+
.inNamespace(cluster.getNamespace())
141+
.resource(cronJob)
142+
.create();
143+
144+
invokeCronJob(client, cronJob);
145+
}
146+
147+
private boolean secretExist(KubernetesClient client) {
148+
SecretList existingSecrets = client.secrets().inNamespace(cluster.getNamespace()).list();
149+
Secret secret = (Secret) KubernetesUtils.findResource(client, existingSecrets, SECRET_NAME);
150+
return secret != null;
151+
}
152+
153+
private void invokeCronJob(KubernetesClient client, CronJob cronJob) {
154+
client.batch().v1()
155+
.jobs()
156+
.inNamespace(cluster.getNamespace())
157+
.resource(new JobBuilder()
158+
.withNewMetadata()
159+
.withName("cronjob-invocation-" + UUID.randomUUID()) //NOI18N
160+
.endMetadata()
161+
.withSpec(cronJob.getSpec().getJobTemplate().getSpec())
162+
.build())
163+
.create();
164+
165+
waitForConditionWithTimeout(() -> {
166+
return secretExist(client);
167+
}, WAITING_TIMEOUT).join();
168+
}
169+
170+
private CompletableFuture<Void> waitForConditionWithTimeout(Supplier<Boolean> condition, long timeout) {
171+
CompletableFuture<Void> future = new CompletableFuture<>();
172+
173+
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
174+
175+
ScheduledFuture<?> checkTask = executor.scheduleAtFixedRate(() -> {
176+
if (condition.get()) {
177+
future.complete(null);
178+
}
179+
}, 0, 5, TimeUnit.SECONDS);
180+
181+
executor.schedule(() -> {
182+
if (!future.isDone()) {
183+
future.completeExceptionally(new TimeoutException("Condition was not met within the timeout.")); //NOI18N
184+
}
185+
checkTask.cancel(true);
186+
executor.shutdown();
187+
}, timeout, TimeUnit.SECONDS);
188+
189+
return future;
190+
}
191+
192+
private String getCronExpression() {
193+
Calendar calendar = Calendar.getInstance();
194+
int currentMinute = calendar.get(Calendar.MINUTE);
195+
return currentMinute + " * * * *";
196+
}
197+
198+
private PodTemplateSpec cronJobPodTemplate(ServiceAccount serviceAccount) {
199+
return new PodTemplateSpecBuilder()
200+
.withNewSpec()
201+
.withHostNetwork(Boolean.TRUE)
202+
.addNewContainer()
203+
.withName(CONTAINER_NAME)
204+
.withImage(BASE_IMAGE)
205+
.addNewEnv()
206+
.withName("OCI_CLI_AUTH") //NOI18N
207+
.withValue("instance_principal") //NOI18N
208+
.endEnv()
209+
.withCommand("/bin/bash", "-c", createSecretCommand()) //NOI18N
210+
.endContainer()
211+
.withRestartPolicy("Never") //NOI18N
212+
.withServiceAccountName(serviceAccount.getMetadata().getName())
213+
.endSpec()
214+
.build();
215+
}
216+
217+
private ServiceAccount createServiceAccountIfNotExist(KubernetesClient client) {
218+
ServiceAccountList existingServiceAccounts = client.serviceAccounts().inNamespace(cluster.getNamespace()).list();
219+
ServiceAccount serviceAccount = (ServiceAccount) KubernetesUtils.findResource(client, existingServiceAccounts, SERVICE_ACCOUNT_NAME);
220+
if (serviceAccount != null) {
221+
return serviceAccount;
222+
}
223+
serviceAccount = new ServiceAccountBuilder()
224+
.withNewMetadata()
225+
.withName(SERVICE_ACCOUNT_NAME)
226+
.endMetadata()
227+
.build();
228+
229+
return client.serviceAccounts()
230+
.inNamespace(cluster.getNamespace())
231+
.resource(serviceAccount)
232+
.create();
233+
}
234+
235+
private void createClusterRoleIfNotExist(KubernetesClient client) {
236+
ClusterRoleList existingClusterRole = client.rbac().clusterRoles().list();
237+
ClusterRole clusterRole = (ClusterRole) KubernetesUtils.findResource(client, existingClusterRole, CLUSTER_ROLE_NAME);
238+
if (clusterRole != null) {
239+
return;
240+
}
241+
clusterRole = new ClusterRoleBuilder()
242+
.withNewMetadata()
243+
.withName(CLUSTER_ROLE_NAME)
244+
.endMetadata()
245+
.addNewRule()
246+
.withApiGroups("")
247+
.withResources("secrets") //NOI18N
248+
.withVerbs("create", "get", "patch", "delete") //NOI18N
249+
.endRule()
250+
.build();
251+
252+
client.rbac().clusterRoles()
253+
.resource(clusterRole)
254+
.create();
255+
}
256+
257+
private void createClusterRoleBindingIfNotExist(KubernetesClient client) {
258+
ClusterRoleBindingList existingClusterRoleBinding = client.rbac().clusterRoleBindings().list();
259+
ClusterRoleBinding clusterRoleBinding = (ClusterRoleBinding) KubernetesUtils.findResource(client, existingClusterRoleBinding, CLUSTER_ROLE_BINDING_NAME);
260+
if (clusterRoleBinding != null) {
261+
return;
262+
}
263+
clusterRoleBinding = new ClusterRoleBindingBuilder()
264+
.withNewMetadata()
265+
.withName(CLUSTER_ROLE_BINDING_NAME)
266+
.endMetadata()
267+
.addNewSubject()
268+
.withName(SERVICE_ACCOUNT_NAME)
269+
.withKind("ServiceAccount") //NOI18N
270+
.withNamespace(cluster.getNamespace())
271+
.endSubject()
272+
.withNewRoleRef()
273+
.withKind("ClusterRole") //NOI18N
274+
.withName(CLUSTER_ROLE_NAME)
275+
.withApiGroup("rbac.authorization.k8s.io") //NOI18N
276+
.endRoleRef()
277+
.build();
278+
279+
client.rbac().clusterRoleBindings()
280+
.resource(clusterRoleBinding)
281+
.create();
282+
}
283+
284+
private String createSecretCommand() {
285+
String repoEndpoint = cluster.getRegionCode() + ".ocir.io"; //NOI18N
286+
return
287+
"KUBECTL_VERSION=\"v1.27.4\"\n" + //NOI18N
288+
"case \"$(uname -m)\" in\n" + //NOI18N
289+
" x86_64) ARCHITECTURE=\"amd64\" ;;\n" + //NOI18N
290+
" aarch64) ARCHITECTURE=\"arm64\" ;;\n" + //NOI18N
291+
" *) ARCHITECTURE=\"Unknown architecture\" ;;\n" + //NOI18N
292+
"esac\n" + //NOI18N
293+
"KUBECTL_URL=\"https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCHITECTURE}/kubectl\"\n" + //NOI18N
294+
"mkdir -p /tmp/bin\n" + //NOI18N
295+
"curl -LO \"${KUBECTL_URL}\"\n" + //NOI18N
296+
"chmod +x ./kubectl\n" + //NOI18N
297+
"mv ./kubectl /tmp/bin/kubectl\n" + //NOI18N
298+
"export PATH=$PATH:/tmp/bin\n" + //NOI18N
299+
"TOKEN=$(oci raw-request --http-method GET --target-uri https://" + repoEndpoint + "/20180419/docker/token | jq -r '.data.token')\n" + //NOI18N
300+
"kubectl create secret --save-config --dry-run=client docker-registry " + SECRET_NAME + " --docker-server=" + repoEndpoint + " --docker-username=BEARER_TOKEN --docker-password=\"$TOKEN\" -o yaml | kubectl apply -f - "; //NOI18N
301+
}
302+
303+
}

‎enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/KubernetesUtils.java

+16
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
import com.oracle.bmc.http.client.Method;
2626
import com.oracle.bmc.http.client.jersey.JerseyHttpProvider;
2727
import com.oracle.bmc.http.signing.RequestSigningFilter;
28+
import io.fabric8.kubernetes.api.model.HasMetadata;
29+
import io.fabric8.kubernetes.api.model.KubernetesResource;
30+
import io.fabric8.kubernetes.api.model.KubernetesResourceList;
31+
import io.fabric8.kubernetes.api.model.batch.v1.CronJob;
32+
import io.fabric8.kubernetes.api.model.batch.v1.CronJobList;
2833
import io.fabric8.kubernetes.client.Config;
2934
import io.fabric8.kubernetes.client.KubernetesClient;
3035
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
@@ -140,4 +145,15 @@ private static String getBearerToken(ClusterItem cluster) {
140145
throw new RuntimeException(ex);
141146
}
142147
}
148+
149+
public static KubernetesResource findResource(KubernetesClient client, KubernetesResourceList<? extends HasMetadata> existingResources, String resourceName) {
150+
if (resourceName == null) return null;
151+
152+
for (HasMetadata resource : existingResources.getItems()) {
153+
if (resourceName.equals(resource.getMetadata().getName())) {
154+
return resource;
155+
}
156+
}
157+
return null;
158+
}
143159
}

‎enterprise/cloud.oracle/src/org/netbeans/modules/cloud/oracle/assets/RunInClusterAction.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@
5656

5757
@NbBundle.Messages({
5858
"RunInCluster=Run in OKE Cluster",
59-
"Deploying=Deploying project \"{0}\" to the cluster \"{1}\""
59+
"Deploying=Deploying project \"{0}\" to the cluster \"{1}\"",
60+
"CreatingSecretRotationCronJob=Creating secret rotation CronJob"
6061
})
6162
public class RunInClusterAction implements ActionListener {
6263

@@ -92,14 +93,14 @@ private void runInCluster() {
9293
}
9394
try {
9495
h.start();
96+
97+
CreateSecretRotationCronJobCommand srcc = new CreateSecretRotationCronJobCommand();
98+
h.progress(Bundle.CreatingSecretRotationCronJob());
99+
srcc.createSecretRotationCronJob().join();
100+
95101
KubernetesUtils.runWithClient(cluster, client -> {
96-
Deployment existingDeployment = null;
97102
DeploymentList dList = client.apps().deployments().inNamespace(cluster.getNamespace()).list();
98-
for (Deployment deployment : dList.getItems()) {
99-
if (projectName.equals(deployment.getMetadata().getName())) {
100-
existingDeployment = deployment;
101-
}
102-
}
103+
Deployment existingDeployment = (Deployment) KubernetesUtils.findResource(client, dList, projectName);
103104
ConfigMapProvider configMapProvider = new ConfigMapProvider(projectName, cluster);
104105
configMapProvider.createConfigMap();
105106

‎ide/jumpto/src/org/netbeans/modules/jumpto/type/GoToTypeAction.java

+2
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,8 @@ private List<? extends TypeDescriptor> getTypeNames(final String text, int[] ret
613613
final TypeProvider.Result result = TypeProviderAccessor.DEFAULT.createResult(items, message, context);
614614
provider.computeTypeNames(context, result);
615615
retry[0] = mergeRetryTimeOut(retry[0], TypeProviderAccessor.DEFAULT.getRetry(result));
616+
} catch (Exception ex) {
617+
LOGGER.log(Level.SEVERE, "Provider ''" + provider.getDisplayName() + "'' yields an exception", ex);
616618
} finally {
617619
current = null;
618620
}

‎java/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.form

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<?xml version="1.1" encoding="UTF-8" ?>
1+
<?xml version="1.0" encoding="UTF-8" ?>
22

33
<!--
44

‎java/java.j2seplatform/src/org/netbeans/modules/java/j2seplatform/libraries/J2SEVolumeCustomizer.java

+20-5
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import org.netbeans.spi.project.libraries.LibraryStorageArea;
6161
import org.netbeans.spi.project.libraries.support.LibrariesSupport;
6262
import org.openide.DialogDescriptor;
63+
import org.openide.filesystems.URLMapper;
6364
import org.openide.util.Utilities;
6465

6566
/**
@@ -532,8 +533,25 @@ private static URI[] pathsToURIs(
532533
@NullAllowed final File baseFolder) throws MalformedURLException, URISyntaxException {
533534
final List<URI> result = new ArrayList<URI>(fileNames.length);
534535
for (String fileName : fileNames) {
535-
final URI uri = pathToURI(baseFolder,fileName,volume);
536-
if (uri != null) {
536+
final URI uri = pathToURI(baseFolder, fileName, volume);
537+
if (volume.equals(J2SELibraryTypeProvider.VOLUME_TYPE_SRC) && (FileUtil.isArchiveFile(uri.toURL()) || FileUtil.isArchiveArtifact(uri.toURL()))) {
538+
// Handle src.jars, that hold the sources for multiple jars (observed for the JDK and OpenJFX)
539+
URL archiveUrl = uri.toURL();
540+
if(FileUtil.isArchiveFile(uri.toURL())) {
541+
archiveUrl = FileUtil.getArchiveRoot(uri.toURL());
542+
}
543+
FileObject archiveFO = URLMapper.findFileObject(archiveUrl);
544+
boolean moduleInfoOnSecondLevel = false;
545+
for (FileObject topLevelFolder : archiveFO.getChildren()) {
546+
if (topLevelFolder.isFolder() && topLevelFolder.getFileObject("module-info.java") != null) {
547+
moduleInfoOnSecondLevel = true;
548+
result.add(topLevelFolder.toURI());
549+
}
550+
}
551+
if(!moduleInfoOnSecondLevel) {
552+
result.add(uri);
553+
}
554+
} else if (uri != null) {
537555
result.add(uri);
538556
}
539557
}
@@ -669,9 +687,6 @@ public Component getListCellRendererComponent(JList list, Object value, int inde
669687
if (uri != null && uri.toString().startsWith("http")) {
670688
displayName = uri.toString();
671689
} else if (uri != null) {
672-
if (uri.toString().contains("!/")) { //NOI18N
673-
uri = LibrariesSupport.getArchiveFile(uri);
674-
}
675690
boolean broken = false;
676691
VolumeContentModel model = (VolumeContentModel)list.getModel();
677692
LibraryStorageArea area = model.getArea();

‎java/java.lsp.server/src/org/netbeans/modules/java/lsp/server/protocol/TextDocumentServiceImpl.java

+11-5
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ public void indexingComplete(Set<URL> indexedRoots) {
349349
private static final int INITIAL_COMPLETION_SAMPLING_DELAY = 1000;
350350
private static final int DEFAULT_COMPLETION_WARNING_LENGTH = 10_000;
351351
private static final RequestProcessor COMPLETION_SAMPLER_WORKER = new RequestProcessor("java-lsp-completion-sampler", 1, false, false);
352+
private static final AtomicReference<Sampler> RUNNING_SAMPLER = new AtomicReference<>();
352353

353354
@Override
354355
@Messages({
@@ -366,11 +367,15 @@ public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completio
366367
if (!done.get()) {
367368
Sampler sampler = Sampler.createSampler("completion");
368369
if (sampler != null) {
369-
sampler.start();
370-
samplerRef.set(sampler);
371-
samplingStart.set(System.currentTimeMillis());
372-
if (done.get()) {
373-
sampler.stop();
370+
Sampler witnessSampler = RUNNING_SAMPLER.compareAndExchange(null, sampler);
371+
372+
if (witnessSampler == null) {
373+
sampler.start();
374+
samplerRef.set(sampler);
375+
samplingStart.set(System.currentTimeMillis());
376+
if (done.get()) {
377+
sampler.stop();
378+
}
374379
}
375380
}
376381
}
@@ -494,6 +499,7 @@ public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completio
494499

495500
done.set(true);
496501
Sampler sampler = samplerRef.get();
502+
RUNNING_SAMPLER.compareAndExchange(sampler, null);
497503
if (sampler != null) {
498504
long samplingTime = (System.currentTimeMillis() - completionStart);
499505
long minSamplingTime = Math.min(1_000, samplingWarningLength.get());

‎nbbuild/javadoctools/template.xml

+3
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,9 @@ cause it to fail.
321321
<bottom>${javadoc.footer}</bottom>
322322
<!-- Avoid timestamp comments in _all_ html generated files, to reduce unnecessary git commits -->
323323
<arg value="-notimestamp" />
324+
<!-- codebase has many occurrences of '///' which were never meant to appear in javadoc
325+
this disables JDK 23+ "line doc comments" for now -->
326+
<arg value="--disable-line-doc-comments" />
324327
<arg value="-Xdoclint:all" />
325328
<arg value="-Xdoclint:-missing" />
326329
</javadoc>

‎platform/o.n.swing.laf.flatlaf/src/org/netbeans/swing/laf/flatlaf/FlatLightLaf.properties

+1
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,4 @@ nb.quicksearch.border=1,1,1,1,@background
8080

8181
# output
8282
nb.output.selectionBackground=#89BCED
83+
nb.output.warning.foreground=#FF9900

0 commit comments

Comments
 (0)
Please sign in to comment.