Skip to content

Commit 9b6f8a0

Browse files
Add javaagent to patch WClipboard
It was observed, that clipboard on windows sometimes reacts flaky. Investigation hints that missing synchronization in the AWT implementation/integration. Testers reported, that the changes implemented here: - the change handling from the system clipboard is dispatched into the event loop and - the change handling is modified to be called synchronized It is expected, that fixing this upstream in the JDK will take longer and so runtime patching must be considered. Runtime patching in this case is accomplished using the javaagent mechanism. The IDE launcher is modified to load an agent, that will intercept loading classes and modify WClipboard while it is being loaded. The transformer is written, so that it will only transform the target class and will act transparantly for all other classes.
1 parent 2e97532 commit 9b6f8a0

File tree

11 files changed

+497
-1
lines changed

11 files changed

+497
-1
lines changed

ide/o.n.agent/build.xml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
- Licensed to the Apache Software Foundation (ASF) under one
4+
- or more contributor license agreements. See the NOTICE file
5+
- distributed with this work for additional information
6+
- regarding copyright ownership. The ASF licenses this file
7+
- to you under the Apache License, Version 2.0 (the
8+
- "License"); you may not use this file except in compliance
9+
- with the License. You may obtain a copy of the License at
10+
-
11+
- http://www.apache.org/licenses/LICENSE-2.0
12+
-
13+
- Unless required by applicable law or agreed to in writing,
14+
- software distributed under the License is distributed on an
15+
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
- KIND, either express or implied. See the License for the
17+
- specific language governing permissions and limitations
18+
- under the License.
19+
-->
20+
<project basedir="." default="netbeans" name="ide/o.n.agent">
21+
<description>Builds, tests, and runs the project org.netbeans.agent</description>
22+
<import file="../../nbbuild/templates/projectized.xml"/>
23+
24+
<target name="-jar-ant">
25+
26+
<mkdir dir="${agent.build.classes.dir}" />
27+
28+
<javac release="${javac.release}"
29+
srcdir="${agent.src.dir}"
30+
destdir="${agent.build.classes.dir}"
31+
debug="true"
32+
classpath="${agent.cp}" />
33+
34+
<jar destfile="${cluster}/netbeans-javaagent.jar" update="true" manifest="${agent.src.dir}/META-INF/MANIFEST.MF">
35+
<fileset dir="${agent.build.classes.dir}" />
36+
<fileset dir="${agent.src.dir}" includes="**/*" excludes="**/*.class" />
37+
<mappedresources>
38+
<fileset file="../../nbbuild/licenses/Apache-2.0" />
39+
<globmapper from="*" to="META-INF/LICENSE"/>
40+
</mappedresources>
41+
<zipfileset src="${agent.asm.lib.1}">
42+
<include name="**" />
43+
<exclude name="module-info.class" />
44+
<exclude name="META-INF/**" />
45+
</zipfileset>
46+
<zipfileset src="${agent.asm.lib.2}">
47+
<include name="**" />
48+
<exclude name="module-info.class" />
49+
<exclude name="META-INF/**" />
50+
</zipfileset>
51+
<zipfileset src="${agent.asm.lib.3}">
52+
<include name="**" />
53+
<exclude name="module-info.class" />
54+
<exclude name="META-INF/**" />
55+
</zipfileset>
56+
</jar>
57+
</target>
58+
59+
<target name="compile" depends="-jar-ant,projectized-common.compile"/>
60+
61+
<target name="clean" depends="projectized-common.clean">
62+
<delete dir="${agent.build.classes.dir}"/>
63+
<delete file="${cluster}/netbeans-javaagent.jar"/>
64+
</target>
65+
</project>

ide/o.n.agent/manifest.mf

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Manifest-Version: 1.0
2+
AutoUpdate-Show-In-Client: true
3+
OpenIDE-Module: org.netbeans.agent
4+
OpenIDE-Module-Localizing-Bundle: org/netbeans/agent/Bundle.properties
5+
OpenIDE-Module-Specification-Version: 1.0
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
18+
javac.release=17
19+
javac.compilerargs=-Xlint -Xlint:-serial
20+
21+
agent.src.dir=src-agent
22+
agent.build.classes.dir=${build.dir}/agent/classes/
23+
agent.jar=${cluster}/netbeans-javaagent.jar
24+
agent.asm.lib.1=../../platform/libs.asm/external/asm-commons-9.8.jar
25+
agent.asm.lib.2=../../platform/libs.asm/external/asm-tree-9.8.jar
26+
agent.asm.lib.3=../../platform/libs.asm/external/asm-9.8.jar
27+
agent.cp=${agent.asm.lib.1}:${agent.asm.lib.2}:${agent.asm.lib.3}
28+
29+
extra.module.files=${cluster}/netbeans-javaagent.jar

ide/o.n.agent/nbproject/project.xml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
- Licensed to the Apache Software Foundation (ASF) under one
4+
- or more contributor license agreements. See the NOTICE file
5+
- distributed with this work for additional information
6+
- regarding copyright ownership. The ASF licenses this file
7+
- to you under the Apache License, Version 2.0 (the
8+
- "License"); you may not use this file except in compliance
9+
- with the License. You may obtain a copy of the License at
10+
-
11+
- http://www.apache.org/licenses/LICENSE-2.0
12+
-
13+
- Unless required by applicable law or agreed to in writing,
14+
- software distributed under the License is distributed on an
15+
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
- KIND, either express or implied. See the License for the
17+
- specific language governing permissions and limitations
18+
- under the License.
19+
-->
20+
<project xmlns="http://www.netbeans.org/ns/project/1">
21+
<type>org.netbeans.modules.apisupport.project</type>
22+
<configuration>
23+
<data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
24+
<code-name-base>org.netbeans.agent</code-name-base>
25+
<module-dependencies>
26+
<dependency>
27+
<code-name-base>org.netbeans.libs.asm</code-name-base>
28+
<build-prerequisite/>
29+
<compile-dependency/>
30+
<run-dependency>
31+
<specification-version>5.31</specification-version>
32+
</run-dependency>
33+
</dependency>
34+
</module-dependencies>
35+
<test-dependencies/>
36+
<public-packages/>
37+
<extra-compilation-unit>
38+
<package-root>${agent.src.dir}</package-root>
39+
<classpath>${agent.cp}</classpath>
40+
<built-to>${agent.build.classes.dir}</built-to>
41+
<built-to>${cluster}/netbeans-javaagent.jar</built-to>
42+
</extra-compilation-unit>
43+
</data>
44+
</configuration>
45+
</project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Premain-Class: org.netbeans.agent.NetBeansAgent
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
Apache NetBeans
2+
Copyright 2017-2025 The Apache Software Foundation
3+
4+
This product includes software developed at
5+
The Apache Software Foundation (http://www.apache.org/).
6+
7+
The code is based on NetBeans, that has been kindly donated to the Apache
8+
Software Foundation by Oracle.
9+
10+
The code was Copyright 1997-2016 Oracle and/or its affiliates. The Initial
11+
Developer of the Original Software was Sun Microsystems, Inc. Portions
12+
Copyright 1997-2006 Sun Microsystems, Inc.
13+
14+
The agent jar embeds a copy of ASM for bytecode manipulation:
15+
16+
*******************************************************************************
17+
* ASM: a very small and fast Java bytecode manipulation framework
18+
* Copyright (c) 2000-2011 INRIA, France Telecom
19+
* All rights reserved.
20+
*
21+
* Redistribution and use in source and binary forms, with or without
22+
* modification, are permitted provided that the following conditions
23+
* are met:
24+
* 1. Redistributions of source code must retain the above copyright
25+
* notice, this list of conditions and the following disclaimer.
26+
* 2. Redistributions in binary form must reproduce the above copyright
27+
* notice, this list of conditions and the following disclaimer in the
28+
* documentation and/or other materials provided with the distribution.
29+
* 3. Neither the name of the copyright holders nor the names of its
30+
* contributors may be used to endorse or promote products derived from
31+
* this software without specific prior written permission.
32+
*
33+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
37+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
43+
* THE POSSIBILITY OF SUCH DAMAGE.
44+
*******************************************************************************
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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.agent;
20+
21+
import java.lang.instrument.ClassFileTransformer;
22+
import java.lang.instrument.Instrumentation;
23+
import java.util.ArrayList;
24+
import java.util.List;
25+
26+
/**
27+
* Implementation of a java agent. The JAR containing this class must be
28+
* referenced by the JVM with the agent infrastructure. At time of writing this
29+
* means, that the JAR must be passed via the `-javaagent:JARPATH` construct.
30+
* JARPATH in this case must be the absolute path to the netbeans-javaagent.jar.
31+
*
32+
* The `premain` method in this class is then invoked by the JVM _before_ the
33+
* applications main method is invoked.
34+
*
35+
* This should be used as a last resort. For classes loaded throught the
36+
* module system that faciliy should be prefered.
37+
*/
38+
public class NetBeansAgent {
39+
40+
public static void premain(String arg, Instrumentation instrumentation) {
41+
List<ClassFileTransformer> transformer = new ArrayList<>(2);
42+
if ((!Boolean.getBoolean(WClipboardTransformer.DEBUG_DISABLE_TRANSFORMER))
43+
&& System.getProperty("os.name").toLowerCase().contains("windows")) {
44+
transformer.add(new WClipboardTransformer(instrumentation));
45+
}
46+
transformer.forEach(cft -> instrumentation.addTransformer(cft, false));
47+
}
48+
49+
}

0 commit comments

Comments
 (0)