8385347: Remove AppContext from SunToolkit and also remove AppContext

Reviewed-by: azvegint, serb, kizune
This commit is contained in:
Phil Race 2026-05-29 17:43:23 +00:00
parent 08ecb87b3d
commit 05244e8d37
23 changed files with 53 additions and 2197 deletions

View File

@ -853,8 +853,10 @@ public class EventQueue {
newEventQueue.previousQueue = topQueue;
topQueue.nextQueue = newEventQueue;
if (SunToolkit.currentEventQueue == topQueue) {
SunToolkit.currentEventQueue = newEventQueue;
synchronized (SunToolkit.class) {
if (SunToolkit.getSystemEventQueueImplPP() == topQueue) {
SunToolkit.currentEventQueue = newEventQueue;
}
}
pushPopCond.signalAll();
@ -913,8 +915,10 @@ public class EventQueue {
topQueue.dispatchThread.setEventQueue(prevQueue);
}
if (SunToolkit.currentEventQueue == this) {
SunToolkit.currentEventQueue = prevQueue;
synchronized (SunToolkit.class) {
if (SunToolkit.getSystemEventQueueImplPP() == this) {
SunToolkit.currentEventQueue = prevQueue;
}
}
// Wake up EDT waiting in getNextEvent(), so it can

View File

@ -125,7 +125,6 @@ public class TrayIcon {
if (!SystemTray.isSupported()) {
throw new UnsupportedOperationException();
}
SunToolkit.insertTargetMapping(this);
}
/**

View File

@ -1,692 +0,0 @@
/*
* Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.awt;
import java.awt.EventQueue;
import java.awt.Window;
import java.awt.SystemTray;
import java.awt.TrayIcon;
import java.awt.Toolkit;
import java.awt.GraphicsEnvironment;
import java.awt.event.InvocationEvent;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
import java.lang.ref.SoftReference;
import sun.util.logging.PlatformLogger;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The AppContext is a table referenced by ThreadGroup which stores
* application service instances. (If you are not writing an application
* service, or don't know what one is, please do not use this class.)
* The AppContext allows a context access to what would otherwise be
* potentially dangerous services, such as the ability to peek at
* EventQueues or change the look-and-feel of a Swing application.<p>
*
* Most application services use a singleton object to provide their
* services, either as a default (such as getSystemEventQueue or
* getDefaultToolkit) or as static methods with class data (System).
* The AppContext works with the former method by extending the concept
* of "default" to be ThreadGroup-specific. Application services
* lookup their singleton in the AppContext.<p>
*
* For example, here we have a Foo service, with its pre-AppContext
* code:<p>
* <pre>{@code
* public class Foo {
* private static Foo defaultFoo = new Foo();
*
* public static Foo getDefaultFoo() {
* return defaultFoo;
* }
*
* ... Foo service methods
* }
* }</pre><p>
*
* The problem with the above is that the Foo service is global in scope,
* so that untrusted code can execute methods on the
* single, shared Foo instance. The Foo service therefore either needs
* to block its use by untrusted code using a SecurityManager test, or
* restrict its capabilities so that it doesn't matter if untrusted code
* executes it.<p>
*
* Here's the Foo class written to use the AppContext:<p>
* <pre>{@code
* public class Foo {
* public static Foo getDefaultFoo() {
* Foo foo = (Foo)AppContext.getAppContext().get(Foo.class);
* if (foo == null) {
* foo = new Foo();
* getAppContext().put(Foo.class, foo);
* }
* return foo;
* }
*
* ... Foo service methods
* }
* }</pre><p>
*
* Since a separate AppContext can exist for each ThreadGroup, trusted
* and untrusted code have access to different Foo instances. This allows
* untrusted code access to "system-wide" services -- the service remains
* within the AppContext "sandbox". For example, say malicious code
* wants to peek all of the key events on the EventQueue to listen for
* passwords; if separate EventQueues are used for each ThreadGroup
* using AppContexts, the only key events that code will be able to
* listen to are its own. A more reasonable request would be to
* change the Swing default look-and-feel; with that default stored in
* an AppContext, the look-and-feel will change without
* disrupting other contexts.
*
* @author Thomas Ball
* @author Fred Ecks
*/
public final class AppContext {
private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.AppContext");
/* Since the contents of an AppContext are unique to each Java
* session, this class should never be serialized. */
/* A map of AppContexts, referenced by ThreadGroup.
*/
private static final Map<ThreadGroup, AppContext> threadGroup2appContext =
Collections.synchronizedMap(new IdentityHashMap<ThreadGroup, AppContext>());
/**
* Returns a set containing all {@code AppContext}s.
*/
public static Set<AppContext> getAppContexts() {
synchronized (threadGroup2appContext) {
return new HashSet<AppContext>(threadGroup2appContext.values());
}
}
/* The main "system" AppContext, used by everything not otherwise
contained in another AppContext. It is implicitly created for
standalone apps only.
*/
private static volatile AppContext mainAppContext;
private static class GetAppContextLock {}
private static final Object getAppContextLock = new GetAppContextLock();
/*
* The hash map associated with this AppContext. A private delegate
* is used instead of subclassing HashMap so as to avoid all of
* HashMap's potentially risky methods, such as clear(), elements(),
* putAll(), etc.
*/
private final Map<Object, Object> table = new HashMap<>();
private final ThreadGroup threadGroup;
/**
* If any {@code PropertyChangeListeners} have been registered,
* the {@code changeSupport} field describes them.
*
* @see #addPropertyChangeListener
* @see #removePropertyChangeListener
* @see PropertyChangeSupport#firePropertyChange
*/
private PropertyChangeSupport changeSupport = null;
public static final String DISPOSED_PROPERTY_NAME = "disposed";
public static final String GUI_DISPOSED = "guidisposed";
private enum State {
VALID,
BEING_DISPOSED,
DISPOSED
}
private volatile State state = State.VALID;
public boolean isDisposed() {
return state == State.DISPOSED;
}
/*
* The total number of AppContexts, system-wide. This number is
* incremented at the beginning of the constructor, and decremented
* at the end of dispose(). getAppContext() checks to see if this
* number is 1. If so, it returns the sole AppContext without
* checking Thread.currentThread().
*/
private static final AtomicInteger numAppContexts = new AtomicInteger();
/*
* The context ClassLoader that was used to create this AppContext.
*/
private final ClassLoader contextClassLoader;
/**
* Constructor for AppContext. This method is <i>not</i> public,
* nor should it ever be used as such. The proper way to construct
* an AppContext is through the use of SunToolkit.createNewAppContext.
* A ThreadGroup is created for the new AppContext, a Thread is
* created within that ThreadGroup, and that Thread calls
* SunToolkit.createNewAppContext before calling anything else.
* That creates both the new AppContext and its EventQueue.
*
* @param threadGroup The ThreadGroup for the new AppContext
* @see sun.awt.SunToolkit
* @since 1.2
*/
AppContext(ThreadGroup threadGroup) {
numAppContexts.incrementAndGet();
this.threadGroup = threadGroup;
threadGroup2appContext.put(threadGroup, this);
this.contextClassLoader = Thread.currentThread().getContextClassLoader();
}
private static final ThreadLocal<AppContext> threadAppContext =
new ThreadLocal<AppContext>();
private static void initMainAppContext() {
// On the main Thread, we get the ThreadGroup, make a corresponding
// AppContext, and instantiate the Java EventQueue. This way, legacy
// code is unaffected by the move to multiple AppContext ability.
ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
while (parentThreadGroup != null) {
// Find the root ThreadGroup to construct our main AppContext
currentThreadGroup = parentThreadGroup;
parentThreadGroup = currentThreadGroup.getParent();
}
mainAppContext = SunToolkit.createNewAppContext(currentThreadGroup);
}
/**
* Returns the appropriate AppContext for the caller,
* as determined by its ThreadGroup.
*
* @return the AppContext for the caller.
* @see java.lang.ThreadGroup
* @since 1.2
*/
public static AppContext getAppContext() {
// we are standalone app, return the main app context
if (numAppContexts.get() == 1 && mainAppContext != null) {
return mainAppContext;
}
AppContext appContext = threadAppContext.get();
if (null == appContext) {
// Get the current ThreadGroup, and look for it and its
// parents in the hash from ThreadGroup to AppContext --
// it should be found, because we use createNewContext()
// when new AppContext objects are created.
ThreadGroup currentThreadGroup = Thread.currentThread().getThreadGroup();
ThreadGroup threadGroup = currentThreadGroup;
// Special case: we implicitly create the main app context
// if no contexts have been created yet.
synchronized (getAppContextLock) {
if (numAppContexts.get() == 0) {
if (System.getProperty("javaplugin.version") == null &&
System.getProperty("javawebstart.version") == null) {
initMainAppContext();
} else if (System.getProperty("javafx.version") != null &&
threadGroup.getParent() != null) {
// Swing inside JavaFX case
SunToolkit.createNewAppContext();
}
}
}
AppContext context = threadGroup2appContext.get(threadGroup);
while (context == null) {
threadGroup = threadGroup.getParent();
if (threadGroup == null) {
// We've got up to the root thread group and did not find an AppContext
// We have nowhere else to look, and this is not supposed to happen.
// return null from this whole method.
return null;
}
context = threadGroup2appContext.get(threadGroup);
}
// In case we did anything in the above while loop, we add
// all the intermediate ThreadGroups to threadGroup2appContext
// so we won't spin again.
for (ThreadGroup tg = currentThreadGroup; tg != threadGroup; tg = tg.getParent()) {
threadGroup2appContext.put(tg, context);
}
// Now we're done, so we cache the latest key/value pair.
threadAppContext.set(context);
appContext = context;
}
return appContext;
}
/**
* Returns true if the specified AppContext is the main AppContext.
*
* @param ctx the context to compare with the main context
* @return true if the specified AppContext is the main AppContext.
* @since 1.8
*/
public static boolean isMainContext(AppContext ctx) {
return (ctx != null && ctx == mainAppContext);
}
private long DISPOSAL_TIMEOUT = 5000; // Default to 5-second timeout
// for disposal of all Frames
// (we wait for this time twice,
// once for dispose(), and once
// to clear the EventQueue).
private long THREAD_INTERRUPT_TIMEOUT = 1000;
// Default to 1-second timeout for all
// interrupted Threads to exit, and another
// 1 second for all stopped Threads to die.
/**
* Disposes of this AppContext, all of its top-level Frames, and
* all Threads and ThreadGroups contained within it.
*
* This method must be called from a Thread which is not contained
* within this AppContext.
*
* @throws IllegalThreadStateException if the current thread is
* contained within this AppContext
* @since 1.2
*/
public void dispose() throws IllegalThreadStateException {
System.err.println(
"""
WARNING: sun.awt.AppContext.dispose() no longer stops threads.
Additionally AppContext will be removed in a future release.
Remove all uses of this internal class as soon as possible.
There is no replacement.
""");
// Check to be sure that the current Thread isn't in this AppContext
if (this.threadGroup.parentOf(Thread.currentThread().getThreadGroup())) {
throw new IllegalThreadStateException(
"Current Thread is contained within AppContext to be disposed."
);
}
synchronized(this) {
if (this.state != State.VALID) {
return; // If already disposed or being disposed, bail.
}
this.state = State.BEING_DISPOSED;
}
final PropertyChangeSupport changeSupport = this.changeSupport;
if (changeSupport != null) {
changeSupport.firePropertyChange(DISPOSED_PROPERTY_NAME, false, true);
}
// First, we post an InvocationEvent to be run on the
// EventDispatchThread which disposes of all top-level Frames and TrayIcons
final Object notificationLock = new Object();
Runnable runnable = new Runnable() {
public void run() {
Window[] windowsToDispose = Window.getOwnerlessWindows();
for (Window w : windowsToDispose) {
try {
w.dispose();
} catch (Throwable t) {
log.finer("exception occurred while disposing app context", t);
}
}
if (!GraphicsEnvironment.isHeadless() && SystemTray.isSupported()) {
SystemTray systemTray = SystemTray.getSystemTray();
TrayIcon[] trayIconsToDispose = systemTray.getTrayIcons();
for (TrayIcon ti : trayIconsToDispose) {
systemTray.remove(ti);
}
}
// Alert PropertyChangeListeners that the GUI has been disposed.
if (changeSupport != null) {
changeSupport.firePropertyChange(GUI_DISPOSED, false, true);
}
synchronized(notificationLock) {
notificationLock.notifyAll(); // Notify caller that we're done
}
}
};
synchronized(notificationLock) {
SunToolkit.postEvent(this,
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
try {
notificationLock.wait(DISPOSAL_TIMEOUT);
} catch (InterruptedException e) { }
}
// Next, we post another InvocationEvent to the end of the
// EventQueue. When it's executed, we know we've executed all
// events in the queue.
runnable = new Runnable() { public void run() {
synchronized(notificationLock) {
notificationLock.notifyAll(); // Notify caller that we're done
}
} };
synchronized(notificationLock) {
SunToolkit.postEvent(this,
new InvocationEvent(Toolkit.getDefaultToolkit(), runnable));
try {
notificationLock.wait(DISPOSAL_TIMEOUT);
} catch (InterruptedException e) { }
}
// We are done with posting events, so change the state to disposed
synchronized(this) {
this.state = State.DISPOSED;
}
// Next, we interrupt all Threads in the ThreadGroup
this.threadGroup.interrupt();
// Note, the EventDispatchThread we've interrupted may dump an
// InterruptedException to the console here. This needs to be
// fixed in the EventDispatchThread, not here.
// Next, we sleep 10ms at a time, waiting for all of the active
// Threads in the ThreadGroup to exit.
long startTime = System.currentTimeMillis();
long endTime = startTime + THREAD_INTERRUPT_TIMEOUT;
while ((this.threadGroup.activeCount() > 0) &&
(System.currentTimeMillis() < endTime)) {
try {
Thread.sleep(10);
} catch (InterruptedException e) { }
}
// Next, we remove this and all subThreadGroups from threadGroup2appContext
int numSubGroups = this.threadGroup.activeGroupCount();
if (numSubGroups > 0) {
ThreadGroup [] subGroups = new ThreadGroup[numSubGroups];
numSubGroups = this.threadGroup.enumerate(subGroups);
for (int subGroup = 0; subGroup < numSubGroups; subGroup++) {
threadGroup2appContext.remove(subGroups[subGroup]);
}
}
threadGroup2appContext.remove(this.threadGroup);
threadAppContext.set(null);
synchronized (table) {
this.table.clear(); // Clear out the Hashtable to ease garbage collection
}
numAppContexts.decrementAndGet();
mostRecentKeyValue = null;
}
private MostRecentKeyValue mostRecentKeyValue = null;
private MostRecentKeyValue shadowMostRecentKeyValue = null;
/**
* Returns the value to which the specified key is mapped in this context.
*
* @param key a key in the AppContext.
* @return the value to which the key is mapped in this AppContext;
* {@code null} if the key is not mapped to any value.
* @see #put(Object, Object)
* @since 1.2
*/
public Object get(Object key) {
/*
* The most recent reference should be updated inside a synchronized
* block to avoid a race when put() and get() are executed in
* parallel on different threads.
*/
synchronized (table) {
// Note: this most recent key/value caching is thread-hot.
// A simple test using SwingSet found that 72% of lookups
// were matched using the most recent key/value. By instantiating
// a simple MostRecentKeyValue object on cache misses, the
// cache hits can be processed without synchronization.
MostRecentKeyValue recent = mostRecentKeyValue;
if ((recent != null) && (recent.key == key)) {
return recent.value;
}
Object value = table.get(key);
if(mostRecentKeyValue == null) {
mostRecentKeyValue = new MostRecentKeyValue(key, value);
shadowMostRecentKeyValue = new MostRecentKeyValue(key, value);
} else {
MostRecentKeyValue auxKeyValue = mostRecentKeyValue;
shadowMostRecentKeyValue.setPair(key, value);
mostRecentKeyValue = shadowMostRecentKeyValue;
shadowMostRecentKeyValue = auxKeyValue;
}
return value;
}
}
/**
* Maps the specified {@code key} to the specified
* {@code value} in this AppContext. Neither the key nor the
* value can be {@code null}.
* <p>
* The value can be retrieved by calling the {@code get} method
* with a key that is equal to the original key.
*
* @param key the AppContext key.
* @param value the value.
* @return the previous value of the specified key in this
* AppContext, or {@code null} if it did not have one.
* @throws NullPointerException if the key or value is
* {@code null}.
* @see #get(Object)
* @since 1.2
*/
public Object put(Object key, Object value) {
synchronized (table) {
MostRecentKeyValue recent = mostRecentKeyValue;
if ((recent != null) && (recent.key == key))
recent.value = value;
return table.put(key, value);
}
}
/**
* Removes the key (and its corresponding value) from this
* AppContext. This method does nothing if the key is not in the
* AppContext.
*
* @param key the key that needs to be removed.
* @return the value to which the key had been mapped in this AppContext,
* or {@code null} if the key did not have a mapping.
* @since 1.2
*/
public Object remove(Object key) {
synchronized (table) {
MostRecentKeyValue recent = mostRecentKeyValue;
if ((recent != null) && (recent.key == key))
recent.value = null;
return table.remove(key);
}
}
/**
* Returns the root ThreadGroup for all Threads contained within
* this AppContext.
* @since 1.2
*/
public ThreadGroup getThreadGroup() {
return threadGroup;
}
/**
* Returns the context ClassLoader that was used to create this
* AppContext.
*
* @see java.lang.Thread#getContextClassLoader
*/
public ClassLoader getContextClassLoader() {
return contextClassLoader;
}
/**
* Returns a string representation of this AppContext.
* @since 1.2
*/
@Override
public String toString() {
return getClass().getName() + "[threadGroup=" + threadGroup.getName() + "]";
}
/**
* Returns an array of all the property change listeners
* registered on this component.
*
* @return all of this component's {@code PropertyChangeListener}s
* or an empty array if no property change
* listeners are currently registered
*
* @see #addPropertyChangeListener
* @see #removePropertyChangeListener
* @see #getPropertyChangeListeners(java.lang.String)
* @see java.beans.PropertyChangeSupport#getPropertyChangeListeners
* @since 1.4
*/
public synchronized PropertyChangeListener[] getPropertyChangeListeners() {
if (changeSupport == null) {
return new PropertyChangeListener[0];
}
return changeSupport.getPropertyChangeListeners();
}
/**
* Adds a PropertyChangeListener to the listener list for a specific
* property. The specified property may be one of the following:
* <ul>
* <li>if this AppContext is disposed ("disposed")</li>
* </ul>
* <ul>
* <li>if this AppContext's unowned Windows have been disposed
* ("guidisposed"). Code to cleanup after the GUI is disposed
* (such as LookAndFeel.uninitialize()) should execute in response to
* this property being fired. Notifications for the "guidisposed"
* property are sent on the event dispatch thread.</li>
* </ul>
* <p>
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName one of the property names listed above
* @param listener the PropertyChangeListener to be added
*
* @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
* @see #getPropertyChangeListeners(java.lang.String)
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
*/
public synchronized void addPropertyChangeListener(
String propertyName,
PropertyChangeListener listener) {
if (listener == null) {
return;
}
if (changeSupport == null) {
changeSupport = new PropertyChangeSupport(this);
}
changeSupport.addPropertyChangeListener(propertyName, listener);
}
/**
* Removes a PropertyChangeListener from the listener list for a specific
* property. This method should be used to remove PropertyChangeListeners
* that were registered for a specific bound property.
* <p>
* If listener is null, no exception is thrown and no action is performed.
*
* @param propertyName a valid property name
* @param listener the PropertyChangeListener to be removed
*
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
* @see #getPropertyChangeListeners(java.lang.String)
* @see PropertyChangeSupport#removePropertyChangeListener(java.beans.PropertyChangeListener)
*/
public synchronized void removePropertyChangeListener(
String propertyName,
PropertyChangeListener listener) {
if (listener == null || changeSupport == null) {
return;
}
changeSupport.removePropertyChangeListener(propertyName, listener);
}
/**
* Returns an array of all the listeners which have been associated
* with the named property.
*
* @return all of the {@code PropertyChangeListeners} associated with
* the named property or an empty array if no listeners have
* been added
*
* @see #addPropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
* @see #removePropertyChangeListener(java.lang.String, java.beans.PropertyChangeListener)
* @see #getPropertyChangeListeners
* @since 1.4
*/
public synchronized PropertyChangeListener[] getPropertyChangeListeners(
String propertyName) {
if (changeSupport == null) {
return new PropertyChangeListener[0];
}
return changeSupport.getPropertyChangeListeners(propertyName);
}
}
final class MostRecentKeyValue {
Object key;
Object value;
MostRecentKeyValue(Object k, Object v) {
key = k;
value = v;
}
void setPair(Object k, Object v) {
key = k;
value = v;
}
}

View File

@ -166,6 +166,7 @@ public abstract class SunToolkit extends Toolkit
}
public SunToolkit() {
initEQ();
}
public boolean useBufferPerWindow() {
@ -258,24 +259,6 @@ public abstract class SunToolkit extends Toolkit
return AWT_LOCK.isHeldByCurrentThread();
}
/*
* Create a new AppContext, along with its EventQueue, for a
* new ThreadGroup.
*/
public static AppContext createNewAppContext() {
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
return createNewAppContext(threadGroup);
}
static final AppContext createNewAppContext(ThreadGroup threadGroup) {
// Create appContext before initialization of EventQueue, so all
// the calls to AppContext.getAppContext() from EventQueue ctor
// return correct values
AppContext appContext = new AppContext(threadGroup);
initEQ();
return appContext;
}
static void wakeupEventQueue(EventQueue q, boolean isShutdown){
AWTAccessor.getEventQueueAccessor().wakeup(q, isShutdown);
}
@ -311,52 +294,6 @@ public abstract class SunToolkit extends Toolkit
}
}
// Maps from non-Component/MenuComponent to AppContext.
// WeakHashMap<Component,AppContext>
private static final Map<Object, AppContext> appContextMap =
Collections.synchronizedMap(new WeakIdentityHashMap<Object, AppContext>());
/**
* Sets the appContext field of target. If target is not a Component or
* MenuComponent, this returns false.
*/
private static boolean setAppContext(Object target,
AppContext context) {
return (target instanceof Component);
}
/**
* Returns the appContext field for target. If target is not a
* Component or MenuComponent this returns null.
*/
private static AppContext getAppContext(Object target) {
if ((target instanceof Component) ||
(target instanceof MenuComponent)) {
return AppContext.getAppContext();
} else {
return null;
}
}
/*
* Fetch the AppContext associated with the given target.
* This can be used to determine things like which EventQueue
* to use for posting events to a Component. If the target is
* null or the target can't be found, a null with be returned.
*/
public static AppContext targetToAppContext(Object target) {
if (target == null) {
return null;
}
AppContext context = getAppContext(target);
if (context == null) {
// target is not a Component/MenuComponent, try the
// appContextMap.
context = appContextMap.get(target);
}
return context;
}
/**
* Sets the synchronous status of focus requests on lightweight
* components in the specified window to the specified value.
@ -394,34 +331,6 @@ public abstract class SunToolkit extends Toolkit
cont.setFocusTraversalPolicy(defaultPolicy);
}
/* This method should be removed at the same time as targetToAppContext() */
public static void insertTargetMapping(Object target) {
insertTargetMapping(target, AppContext.getAppContext());
}
/*
* Insert a mapping from target to AppContext, for later retrieval
* via targetToAppContext() above.
*/
public static void insertTargetMapping(Object target, AppContext appContext) {
if (!setAppContext(target, appContext)) {
// Target is not a Component/MenuComponent, use the private Map
// instead.
appContextMap.put(target, appContext);
}
}
public static void postEvent(AWTEvent event) {
/* Adding AppContext is temporary to help migrate away from using app contexts
* It is used by code which has already been subject to that migration.
* However until that is complete, there is a single main app context we
* can retrieve to use which would be the same as if the code had
* not been migrated.
* The overload which accepts the AppContext will eventually be replaced by this.
*/
postEvent(AppContext.getAppContext(), event);
}
/*
* Post an AWTEvent to the Java EventQueue, using the PostEventQueue
* to avoid possibly calling client code (EventQueueSubclass.postEvent())
@ -429,7 +338,7 @@ public abstract class SunToolkit extends Toolkit
* not be called under another lock since it locks the EventQueue.
* See bugids 4632918, 4526597.
*/
public static void postEvent(AppContext appContext, AWTEvent event) {
public static void postEvent(AWTEvent event) {
if (event == null) {
throw new NullPointerException();
}
@ -468,7 +377,7 @@ public abstract class SunToolkit extends Toolkit
((Component)e.getSource()).dispatchEvent(e);
}
}, PeerEvent.ULTIMATE_PRIORITY_EVENT);
postEvent(targetToAppContext(e.getSource()), pe);
postEvent(pe);
}
/*
@ -513,25 +422,18 @@ public abstract class SunToolkit extends Toolkit
* returning to the caller.
*/
public static void executeOnEventHandlerThread(PeerEvent peerEvent) {
postEvent(targetToAppContext(peerEvent.getSource()), peerEvent);
postEvent(peerEvent);
}
public static void invokeLater(Runnable dispatcher) {
invokeLaterOnAppContext(AppContext.getAppContext(), dispatcher);
}
/*
* Execute a chunk of code on the Java event handler thread. The
* method takes into account provided AppContext and sets
* {@code SunToolkit.getDefaultToolkit()} as a target of the
* method sets {@code SunToolkit.getDefaultToolkit()} as a target of the
* event. See 6451487 for details.
* Does not wait for the execution to occur before returning to
* the caller.
*/
public static void invokeLaterOnAppContext(
AppContext appContext, Runnable dispatcher)
{
postEvent(appContext,
public static void invokeLater(Runnable dispatcher) {
postEvent(
new PeerEvent(Toolkit.getDefaultToolkit(), dispatcher,
PeerEvent.PRIORITY_EVENT));
}
@ -1479,8 +1381,7 @@ public abstract class SunToolkit extends Toolkit
final AtomicBoolean eventDispatched = new AtomicBoolean();
synchronized (waitLock) {
queueWasEmpty = isEQEmpty();
postEvent(AppContext.getAppContext(),
new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
postEvent(new PeerEvent(getSystemEventQueueImpl(), null, PeerEvent.LOW_PRIORITY_EVENT) {
@Override
public void dispatch() {
// Here we block EDT. It could have some

View File

@ -478,8 +478,6 @@ final class XSelection {
int count = 0;
try {
SunToolkit.insertTargetMapping(this);
byteData = DataTransferer.getInstance().convertData(this,
contents,
format,

View File

@ -33,8 +33,7 @@ import sun.awt.UngrabEvent;
/**
* This class provides static utility methods to be used by FX swing interop
* to access and use jdk internal classes like SunToolkit, AppContext
* and UngrabEvent.
* to access and use jdk internal classes like SunToolkit and UngrabEvent.
*
* @since 11
*/

View File

@ -142,7 +142,6 @@ java/awt/Focus/ToFrontFocusTest/ToFrontFocus.java 7156130 linux-all
java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java 8169096 macosx-all
java/awt/Focus/TestDisabledAutoTransfer.java 8159871 macosx-all,windows-all
java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all
java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all
java/awt/Focus/FocusPolicyTest.java 7160904 linux-all
java/awt/Graphics/SmallPrimitives.java 8047070 macosx-all,linux-all
java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -44,7 +44,6 @@ import java.awt.event.WindowEvent;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import sun.awt.SunToolkit;
import sun.awt.AppContext;
public class JaWSTest implements ActionListener, Runnable {
@ -52,7 +51,6 @@ public class JaWSTest implements ActionListener, Runnable {
static volatile JaWSTest worker;
static volatile Dialog dummyDialog;
static final Object signalObject = new Object();
static volatile AppContext appContextObject = null;
static volatile Button button = null;
static final CountDownLatch dialogFinished = new CountDownLatch(1);
@ -115,9 +113,6 @@ public class JaWSTest implements ActionListener, Runnable {
e.printStackTrace();
dummyDialog.setVisible(false);
}
if (appContextObject != null) {
appContextObject = null;
}
dummyDialog.dispose();
}
System.err.println("Show Something");
@ -127,21 +122,17 @@ public class JaWSTest implements ActionListener, Runnable {
public void run() {
System.err.println("Running");
try {
appContextObject = SunToolkit.createNewAppContext();
} finally {
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.err.println("Before Hiding 1");
dummyDialog.setVisible(false);
System.err.println("Before Synchronized");
synchronized (signalObject) {
System.err.println("In Synchronized");
signalObject.notify();
System.err.println("After Notify");
}
Thread.sleep(1000);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.err.println("Before Hiding 1");
dummyDialog.setVisible(false);
System.err.println("Before Synchronized");
synchronized (signalObject) {
System.err.println("In Synchronized");
signalObject.notify();
System.err.println("After Notify");
}
System.err.println("Stop Running");
}

View File

@ -1,60 +0,0 @@
/*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8004584
* @summary Tests 8004584
* @author anthony.petrov@oracle.com, petr.pchelko@oracle.com
* @modules java.desktop/sun.awt
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import sun.awt.*;
public class MainAppContext {
public static void main(String[] args) {
ThreadGroup secondGroup = new ThreadGroup("test");
new Thread(secondGroup, () -> {
SunToolkit.createNewAppContext();
test(true);
}).start();
// Sleep on the main thread so that the AWT Toolkit is initialized
// in a user AppContext first
try { Thread.sleep(2000); } catch (Exception e) {}
test(false);
}
private static void test(boolean expectAppContext) {
boolean appContextIsCreated = AppContext.getAppContext() != null;
if (expectAppContext != appContextIsCreated) {
throw new RuntimeException("AppContext is created: " + appContextIsCreated
+ " expected: " + expectAppContext);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -33,7 +33,6 @@
import java.awt.*;
import java.awt.event.*;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
public class PostEventOrderingTest {
@ -45,11 +44,11 @@ public class PostEventOrderingTest {
for (int j = 0; j < 100; j++) {
q.postEvent(new PostActionEvent());
for (int k = 0; k < 10; k++) {
SunToolkit.postEvent(AppContext.getAppContext(), new PostActionEvent());
SunToolkit.postEvent(new PostActionEvent());
}
}
for (int k = 0; k < 100; k++) {
SunToolkit.postEvent(AppContext.getAppContext(), new PostActionEvent());
SunToolkit.postEvent(new PostActionEvent());
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,7 +66,7 @@ public class PushPopTest {
};
InvocationEvent ie = new InvocationEvent(eq2, runnable, null, false);
// System.err.println(ie);
SunToolkit.postEvent(SunToolkit.targetToAppContext(frame), ie);
SunToolkit.postEvent(ie);
eq1.pop();
frame.dispose();
}
@ -94,7 +94,7 @@ class MyEventQueue2 extends EventQueue {
}
};
InvocationEvent ie = new InvocationEvent(MyEventQueue2.this, runnable, null, false);
SunToolkit.postEvent(SunToolkit.targetToAppContext(PushPopTest.frame), ie);
SunToolkit.postEvent(ie);
postEvent(ie);
}
});

View File

@ -1,245 +0,0 @@
/*
* Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6385277
* @key headful
* @summary Tests that activation happens on correct AppContext.
* @modules java.desktop/sun.awt
* @run main ActivateOnProperAppContextTest
*/
import sun.awt.AppContext;
import sun.awt.SunToolkit;
import java.awt.Button;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
import java.awt.Point;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.InputEvent;
import java.util.concurrent.atomic.AtomicBoolean;
public class ActivateOnProperAppContextTest {
static Robot robot;
SunToolkit toolkit;
ThreadGroup threadGroup = new ThreadGroup("Test_Thread_Group");
AppContext appContext;
Frame frame;
volatile boolean passed = true;
AtomicBoolean cond = new AtomicBoolean(false);
public static void main(String[] args) throws Exception {
ActivateOnProperAppContextTest app = new ActivateOnProperAppContextTest();
robot = new Robot();
app.start();
}
public void start() {
toolkit = (SunToolkit)Toolkit.getDefaultToolkit();
Runnable runnable = new Runnable() {
public void run() {
test();
synchronized (cond) {
cond.set(true);
cond.notifyAll();
}
}
};
Thread thread = new Thread(threadGroup, runnable, "Test Thread");
synchronized (cond) {
thread.start();
while (!cond.get()) {
try {
cond.wait();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
if (passed) {
System.out.println("Test passed.");
} else {
throw new TestFailedException("Test failed!");
}
}
void test() {
appContext = SunToolkit.createNewAppContext();
System.out.println("Created new AppContext: " + appContext);
frame = new Frame("ActivateOnProperAppContextTest Frame") {
public boolean isActive() {
verifyAppContext("Frame.isActive()");
return super.isActive();
}
public boolean isFocused() {
verifyAppContext("Frame.isFocused()");
return super.isFocused();
}
public boolean isFocusable() {
verifyAppContext("Frame.isFocusable()");
return super.isFocusable();
}
public Window getOwner() {
verifyAppContext("Frame.getOwner()");
return super.getOwner();
}
public boolean isEnabled() {
verifyAppContext("Frame.isEnabled()");
return super.isEnabled();
}
public boolean isVisible() {
verifyAppContext("Frame.isVisible()");
return super.isVisible();
}
public Container getParent() {
verifyAppContext("Frame.getParent()");
return super.getParent();
}
public Cursor getCursor() {
verifyAppContext("Frame.getCursor()");
return super.getCursor();
}
public Point getLocation() {
verifyAppContext("Frame.getLocation()");
return super.getLocation();
}
public Point getLocationOnScreen() {
verifyAppContext("Frame.getLocationOnScreen()");
return super.getLocationOnScreen();
}
};
Window window = new Window(frame) {
public boolean isFocused() {
verifyAppContext("Window.isFocused()");
return super.isFocused();
}
public boolean isFocusable() {
verifyAppContext("Window.isFocusable()");
return super.isFocusable();
}
public Window getOwner() {
verifyAppContext("Window.getOwner()");
return super.getOwner();
}
public boolean isEnabled() {
verifyAppContext("Window.isEnabled()");
return super.isEnabled();
}
public boolean isVisible() {
verifyAppContext("Window.isVisible()");
return super.isVisible();
}
public Container getParent() {
verifyAppContext("Window.getParent()");
return super.getParent();
}
public Cursor getCursor() {
verifyAppContext("Window.getCursor()");
return super.getCursor();
}
public Point getLocation() {
verifyAppContext("Window.getLocation()");
return super.getLocation();
}
public Point getLocationOnScreen() {
verifyAppContext("Window.getLocationOnScreen()");
return super.getLocationOnScreen();
}
};
Button button = new Button("button");
Label label = new Label("label");
window.setLayout(new FlowLayout());
window.add(button);
window.add(label);
window.setLocation(800, 0);
window.pack();
window.setVisible(true);
frame.setBounds(800, 100, 100, 50);
frame.setVisible(true);
toolkit.realSync();
/*
* When the label is clicked in the window some of
* the owner's public method get called.
*/
clickOn(label);
}
void verifyAppContext(String methodName) {
AppContext ac = AppContext.getAppContext();
println(methodName + " called on AppContext: " + ac);
if (ac != appContext) {
passed = false;
System.err.println("Test failed: " + methodName + " is called on wrong AppContext!");
Thread.dumpStack();
}
}
void clickOn(Component c) {
Point p = c.getLocationOnScreen();
Dimension d = c.getSize();
robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2));
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(20);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
toolkit.realSync();
}
void println(final String msg) {
SunToolkit.executeOnEventHandlerThread(frame, new Runnable() {
public void run() {
System.out.println(msg);
}
});
}
}
class TestFailedException extends RuntimeException {
TestFailedException(String msg) {
super(msg);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,8 +27,7 @@
* @bug 8013563 8028486
* @summary Tests that windows are removed from windows list
* @library /javax/swing/regtesthelpers
* @modules java.desktop/sun.awt
* java.desktop/sun.java2d
* @modules java.desktop/sun.java2d
* @build Util
* @run main/othervm -Xms32M -Xmx32M WindowsLeak
*/
@ -39,7 +38,6 @@ import java.awt.Window;
import java.lang.ref.WeakReference;
import java.util.Vector;
import sun.awt.AppContext;
import sun.java2d.Disposer;
public class WindowsLeak {
@ -61,11 +59,10 @@ public class WindowsLeak {
Util.generateOOME();
}
Vector<WeakReference<Window>> windowList =
(Vector<WeakReference<Window>>) AppContext.getAppContext().get(Window.class);
Window[] windowList = Window.getWindows();
if (windowList != null && !windowList.isEmpty()) {
throw new RuntimeException("Test FAILED: Window list is not empty: " + windowList.size());
if (windowList != null && (windowList.length != 0)) {
throw new RuntimeException("Test FAILED: Window list is not empty: " + windowList.length);
}
System.out.println("Test PASSED");

View File

@ -1,84 +0,0 @@
/*
* Copyright (c) 2013, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.logging.Logger;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
/**
* @test
* @bug 8026404
* @summary checks that calling getLogger() from a Thread whose ThreadGroup is
* a child of the main root group doesn't throw an exception.
* @modules java.desktop/sun.awt
* java.logging
* @build TestMainAppContext
* @run main/othervm TestMainAppContext
* @author danielfuchs
*/
public class TestMainAppContext {
static volatile Throwable thrown = null;
public static void main(String... args) throws Exception {
ThreadGroup rootTG = Thread.currentThread().getThreadGroup();
while (rootTG.getParent() != null) {
rootTG = rootTG.getParent();
}
ThreadGroup tg = new ThreadGroup(rootTG, "main");
final Thread t1 = new Thread(tg, "child") {
@Override
public void run() {
try {
AppContext context = SunToolkit.createNewAppContext();
} catch(Throwable t) {
thrown = t;
}
}
};
t1.start();
t1.join();
if (thrown != null) {
throw new RuntimeException("Unexpected exception: " + thrown, thrown);
}
Thread t2 = new Thread(tg, "BugDetector") {
@Override
public void run() {
try {
Logger.getLogger("foo").info("Done");
} catch (Throwable x) {
thrown = x;
}
}
};
t2.start();
t2.join();
if (thrown != null) {
throw new RuntimeException("Test failed: " + thrown, thrown);
}
}
}

View File

@ -1,224 +0,0 @@
#!/bin/ksh -p
#
# Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
# or visit www.oracle.com if you need additional information or have any
# questions.
#
#
# @test
# @bug 6788096
# @key intermittent
# @summary Test simulates the case of multiple applets executed in
# the same VM and verifies that ImageIO shutdown hook
# StreamCloser does not cause a leak of classloaders.
#
# @modules java.desktop/sun.awt
# @build test.Main
# @build testapp.Main
# @run shell run_test.sh
# There are several resources which need to be present before many
# shell scripts can run. Following are examples of how to check for
# many common ones.
#
# Note that the shell used is the Korn Shell, KSH
#
# Also note, it is recommended that make files NOT be used. Rather,
# put the individual commands directly into this file. That way,
# it is possible to use command line arguments and other shell tech-
# niques to find the compiler, etc on different systems. For example,
# a different path could be used depending on whether this were a
# Solaris or Win32 machine, which is more difficult (if even possible)
# in a make file.
# Beginning of subroutines:
status=1
#Call this from anywhere to fail the test with an error message
# usage: fail "reason why the test failed"
fail()
{ echo "The test failed :-("
echo "$*" 1>&2
echo "exit status was $status"
exit $status
} #end of fail()
#Call this from anywhere to pass the test with a message
# usage: pass "reason why the test passed if applicable"
pass()
{ echo "The test passed!!!"
echo "$*" 1>&2
exit 0
} #end of pass()
# end of subroutines
# The beginning of the script proper
# Checking for proper OS
OS=`uname -s`
case "$OS" in
Linux )
VAR="A different value for Linux"
DEFAULT_JDK=/
FILESEP="/"
PATHSEP=":"
TMP="/tmp"
;;
AIX )
VAR="A different value for AIX"
DEFAULT_JDK=/
FILESEP="/"
PATHSEP=":"
TMP="/tmp"
;;
Darwin )
VAR="A different value for MacOSX"
DEFAULT_JDK=/usr
FILESEP="/"
PATHSEP=":"
TMP="/tmp"
;;
Windows* )
VAR="A different value for Win32"
DEFAULT_JDK="C:/Program Files/Java/jdk1.8.0"
FILESEP="\\"
PATHSEP=";"
TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}`
;;
CYGWIN* )
VAR="A different value for Cygwin"
DEFAULT_JDK="/cygdrive/c/Program\ Files/Java/jdk1.8.0"
FILESEP="/"
PATHSEP=";"
TMP=`cd "${SystemRoot}/Temp"; echo ${PWD}`
;;
# catch all other OSs
* )
echo "Unrecognized system! $OS"
fail "Unrecognized system! $OS"
;;
esac
# Want this test to run standalone as well as in the harness, so do the
# following to copy the test's directory into the harness's scratch directory
# and set all appropriate variables:
if [ -z "${TESTJAVA}" ] ; then
# TESTJAVA is not set, so the test is running stand-alone.
# TESTJAVA holds the path to the root directory of the build of the JDK
# to be tested. That is, any java files run explicitly in this shell
# should use TESTJAVA in the path to the java interpreter.
# So, we'll set this to the JDK spec'd on the command line. If none
# is given on the command line, tell the user that and use a cheesy
# default.
# THIS IS THE JDK BEING TESTED.
if [ -n "$1" ] ;
then TESTJAVA=$1
else echo "no JDK specified on command line so using default!"
TESTJAVA=$DEFAULT_JDK
fi
TESTSRC=.
TESTCLASSES=.
STANDALONE=1;
fi
echo "JDK under test is: $TESTJAVA"
############### YOUR TEST CODE HERE!!!!!!! #############
#All files required for the test should be in the same directory with
# this file. If converting a standalone test to run with the harness,
# as long as all files are in the same directory and it returns 0 for
# pass, you should be able to cut and paste it into here and it will
# run with the test harness.
# This is an example of running something -- test
# The stuff below catches the exit status of test then passes or fails
# this shell test as appropriate ( 0 status is considered a pass here )
echo "Create TestApp.jar..."
if [ -f TestApp.jar ] ; then
rm -f TestApp.jar
fi
${TESTJAVA}/bin/jar -cvf TestApp.jar -C ${TESTCLASSES} testapp
if [ $? -ne "0" ] ; then
fail "Failed to create TestApp.jar"
fi
echo "Create Test.jar..."
if [ -f Test.jar ] ; then
rm -f Test.jar
fi
${TESTJAVA}/bin/jar -cvf Test.jar -C ${TESTCLASSES} test
if [ $? -ne 0 ] ; then
fail "Failed to create Test.jar"
fi
# Prepare temp dir for cahce files
mkdir ./tmp
if [ $? -ne 0 ] ; then
fail "Unable to create temp directory."
fi
# Verify that all classloaders are destroyed
${TESTJAVA}/bin/java --add-exports java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} -cp Test.jar test.Main
if [ $? -ne 0 ] ; then
fail "Test FAILED: some classloaders weren't destroyed."
fi
# Verify that ImageIO shutdown hook works correcly
${TESTJAVA}/bin/java --add-exports java.desktop/sun.awt=ALL-UNNAMED ${TESTVMOPTS} \
-cp Test.jar -DforgetSomeStreams=true test.Main
if [ $? -ne 0 ] ; then
fail "Test FAILED: some classloaders weren't destroyed of shutdown hook failed."
fi
# sanity check: verify that all cache files were deleted
cache_files=`ls tmp`
if [ "x${cache_files}" != "x" ] ; then
echo "WARNING: some cache files was not deleted: ${cache_files}"
fi
echo "Test done."
status=$?
if [ $status -eq "0" ] ; then
pass ""
else
fail "Test failed due to test plugin was not found."
fi

View File

@ -1,284 +0,0 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package test;
import java.io.File;
import java.io.IOException;
import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import javax.imageio.stream.ImageInputStream;
import sun.awt.AppContext;
import sun.awt.SunToolkit;
public class Main {
private static ThreadGroup appsThreadGroup;
private static WeakHashMap<MyClassLoader, String> refs =
new WeakHashMap<MyClassLoader, String>();
/** Collection to simulate forgrotten streams **/
private static HashMap<String, ImageInputStream> strongRefs =
new HashMap<String, ImageInputStream>();
private static ConcurrentLinkedQueue<Throwable> problems =
new ConcurrentLinkedQueue<Throwable>();
private static AppContext mainAppContext = null;
private static CountDownLatch doneSignal;
private static final int gcTimeout =
Integer.getInteger("gcTimeout", 10).intValue();
private static boolean forgetSomeStreams =
Boolean.getBoolean("forgetSomeStreams");
public static void main(String[] args) throws IOException {
mainAppContext = SunToolkit.createNewAppContext();
System.out.println("Current context class loader: " +
Thread.currentThread().getContextClassLoader());
appsThreadGroup = new ThreadGroup("MyAppsThreadGroup");
File jar = new File("TestApp.jar");
if (!jar.exists()) {
System.out.println(jar.getAbsolutePath() + " was not found!\n" +
"Please install the jar with test application correctly!");
throw new RuntimeException("Test failed: no TestApp.jar");
}
URL[] urls = new URL[]{jar.toURL()};
int numApps = Integer.getInteger("numApps", 20).intValue();
doneSignal = new CountDownLatch(numApps);
int cnt = 0;
while (cnt++ < numApps) {
launch(urls, "testapp.Main", "launch");
checkErrors();
}
System.out.println("Wait for apps completion....");
try {
doneSignal.await();
} catch (InterruptedException e) {
}
System.out.println("All apps finished.");
System.gc();
System.out.flush();
System.out.println("Enumerate strong refs:");
for (String is : strongRefs.keySet()) {
System.out.println("-> " + is);
}
System.out.println("=======================");
// wait few seconds
waitAndGC(gcTimeout);
doneSignal = new CountDownLatch(1);
Runnable workaround = new Runnable() {
public void run() {
AppContext ctx = null;
try {
ctx = SunToolkit.createNewAppContext();
} catch (Throwable e) {
// ignore...
} finally {
doneSignal.countDown();
}
}
};
Thread wt = new Thread(appsThreadGroup, workaround, "Workaround");
wt.setContextClassLoader(new MyClassLoader(urls, "workaround"));
wt.start();
wt = null;
workaround = null;
System.out.println("Wait for workaround completion...");
try {
doneSignal.await();
} catch (InterruptedException e) {
}
// give a chance to GC
waitAndGC(gcTimeout);
if (!refs.isEmpty()) {
System.out.println("Classloaders still alive:");
for (MyClassLoader l : refs.keySet()) {
String val = refs.get(l);
if (val == null) {
throw new RuntimeException("Test FAILED: Invalid classloader name");
}
System.out.println("->" + val + (strongRefs.get(val) != null ?
" (has strong ref)" : ""));
if (strongRefs.get(val) == null) {
throw new RuntimeException("Test FAILED: exta class loader is detected! ");
}
}
} else {
System.out.println("No alive class loaders!!");
}
System.out.println("Test PASSED.");
}
private static void waitAndGC(int sec) {
int cnt = sec;
System.out.print("Wait ");
while (cnt-- > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
// do GC every 3 seconds
if (cnt % 3 == 2) {
System.gc();
System.out.print("+");
} else {
System.out.print(".");
}
checkErrors();
}
System.out.println("");
}
private static void checkErrors() {
while (!problems.isEmpty()) {
Throwable theProblem = problems.poll();
System.out.println("Test FAILED!");
do {
theProblem.printStackTrace(System.out);
theProblem = theProblem.getCause();
} while (theProblem != null);
throw new RuntimeException("Test FAILED");
}
}
static int counter = 0;
private static void launch(URL[] urls, final String className,
final String methodName)
{
final String uniqClassName = "testapp/Uniq" + counter;
final boolean saveStrongRef = forgetSomeStreams ? (counter % 5 == 4) : false;
System.out.printf("%s: launch the app\n", uniqClassName);
Runnable launchIt = new Runnable() {
public void run() {
AppContext ctx = SunToolkit.createNewAppContext();
try {
Class appMain =
ctx.getContextClassLoader().loadClass(className);
Method launch = appMain.getDeclaredMethod(methodName,
strongRefs.getClass());
Constructor c = appMain.getConstructor(String.class,
problems.getClass());
Object o = c.newInstance(uniqClassName, problems);
if (saveStrongRef) {
System.out.printf("%s: force strong ref\n",
uniqClassName);
launch.invoke(o, strongRefs);
} else {
HashMap<String, ImageInputStream> empty = null;
launch.invoke(o, empty);
}
ctx = null;
} catch (Throwable e) {
problems.add(e);
} finally {
doneSignal.countDown();
}
}
};
MyClassLoader appClassLoader = new MyClassLoader(urls, uniqClassName);
refs.put(appClassLoader, uniqClassName);
Thread appThread = new Thread(appsThreadGroup, launchIt,
"AppThread" + counter++);
appThread.setContextClassLoader(appClassLoader);
appThread.start();
launchIt = null;
appThread = null;
appClassLoader = null;
}
private static class MyClassLoader extends URLClassLoader {
private static boolean verbose =
Boolean.getBoolean("verboseClassLoading");
private String uniqClassName;
public MyClassLoader(URL[] urls, String uniq) {
super(urls);
uniqClassName = uniq;
}
public Class loadClass(String name) throws ClassNotFoundException {
if (verbose) {
System.out.printf("%s: load class %s\n", uniqClassName, name);
}
if (uniqClassName.equals(name)) {
return Object.class;
}
return super.loadClass(name);
}
public String toString() {
return "MyClassLoader(" + uniqClassName + ")";
}
}
}

View File

@ -1,109 +0,0 @@
/*
* Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package testapp;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.imageio.stream.FileCacheImageInputStream;
import javax.imageio.stream.ImageInputStream;
public class Main {
public static void main(String[] args) {
Main o = new Main("testapp.some.class", null);
o.launch(null);
}
private final String uniqClassName;
private final ConcurrentLinkedQueue<Throwable> problems;
public Main(String uniq, ConcurrentLinkedQueue<Throwable> p) {
uniqClassName = uniq;
problems = p;
}
public void launch(HashMap<String, ImageInputStream> refs) {
System.out.printf("%s: current context class loader: %s\n",
uniqClassName,
Thread.currentThread().getContextClassLoader());
try {
byte[] data = new byte[1024];
ByteArrayInputStream bais = new ByteArrayInputStream(data);
MyImageInputStream iis = new MyImageInputStream(bais,
uniqClassName,
problems);
if (refs != null) {
System.out.printf("%s: added to strong store\n",
uniqClassName);
refs.put(uniqClassName, iis);
}
iis.read();
//leave stream open : let's shutdown hook work!
} catch (IOException e) {
problems.add(e);
}
}
private static class MyImageInputStream extends FileCacheImageInputStream {
private final String uniqClassName;
private ConcurrentLinkedQueue<Throwable> problems;
public MyImageInputStream(InputStream is, String uniq,
ConcurrentLinkedQueue<Throwable> p) throws IOException
{
super(is, new File("tmp"));
uniqClassName = uniq;
problems = p;
}
@Override
public void close() throws IOException {
Test t = new Test();
try {
t.doTest(uniqClassName);
} catch (Throwable e) {
problems.add(e);
}
super.close();
problems = null;
}
}
}
class Test {
public void doTest(String uniqClassName) throws ClassNotFoundException {
System.out.printf("%s: Current thread: %s\n", uniqClassName,
Thread.currentThread());
ClassLoader thisCL = this.getClass().getClassLoader();
Class uniq = thisCL.loadClass(uniqClassName);
System.out.printf("%s: test is done!\n",uniqClassName);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,12 +27,9 @@
* @bug 7004134
* @summary JLabel containing a ToolTipText does no longer show ToolTip after browser refresh
* @author Pavel Porvatov
* @modules java.desktop/sun.awt
* @modules java.desktop/javax.swing:open
*/
import sun.awt.SunToolkit;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
@ -45,7 +42,12 @@ public class bug7004134 {
private static volatile int toolTipWidth;
private static Robot robot;
public static void main(String[] args) throws Exception {
robot = new Robot();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
label = new JLabel("A JLabel used as object for an HTML-formatted tooltip");
@ -59,7 +61,7 @@ public class bug7004134 {
}
});
((SunToolkit) SunToolkit.getDefaultToolkit()).realSync();
robot.waitForIdle();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
@ -82,7 +84,6 @@ public class bug7004134 {
Thread thread = new Thread(new ThreadGroup("Some ThreadGroup"), new Runnable() {
public void run() {
SunToolkit.createNewAppContext();
try {
SwingUtilities.invokeAndWait(new Runnable() {
@ -96,7 +97,7 @@ public class bug7004134 {
}
});
((SunToolkit) SunToolkit.getDefaultToolkit()).realSync();
robot.waitForIdle();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,8 +29,6 @@
* @modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import java.awt.event.ActionEvent;
import java.util.Set;
import javax.swing.JSplitPane;
@ -60,7 +58,6 @@ public class Test6657026 extends BasicSplitPaneUI implements Runnable {
}
public void run() {
SunToolkit.createNewAppContext();
if (new JSplitPane().getFocusTraversalKeys(0).isEmpty()) {
throw new Error("shared traversal keys");
}

View File

@ -1,229 +0,0 @@
/*
* Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4969419
* @summary Tests that generated disabled icons have same look with Ocean
* and are updated when theme is switched
* @modules java.desktop/sun.awt
* @library /java/awt/regtesthelpers
* @build PassFailJFrame
* @key headful
* @run main/manual bug4969419
*/
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.JToggleButton;
import javax.swing.LookAndFeel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.plaf.metal.DefaultMetalTheme;
import javax.swing.plaf.metal.MetalLookAndFeel;
import javax.swing.plaf.metal.MetalTheme;
import sun.awt.AppContext;
public class bug4969419 {
static final String INSTRUCTIONS = """
When the test starts you'll see several components with icons.
Use the bottom combo box and the "Set" button to switch between
the Ocean theme and DefaultMetalTheme.
1. Set the Ocean theme. Ensure all the icons are the same
Note that they all are of the same brightness: none of them
can be brighter or darker than the others.
2. Switch to DefaultMetalTheme. Ensure all the icons changed
(became slightly darker).
3. Switch back to Ocean. Ensure all the icons changed
(became brighter).
""";
public static void main(String[] args) throws Exception {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
PassFailJFrame.builder()
.title("bug4969419 Test Instructions")
.instructions(INSTRUCTIONS)
.columns(40)
.testUI(bug4969419::createUI)
.build()
.awaitAndCheck();
}
static JFrame createUI() {
JFrame frame = new JFrame("Metal Themes Icon Test");
Container pane = frame.getContentPane();
LFSwitch lfswitch = new LFSwitch(pane);
if (!lfswitch.obtainOceanTheme()) {
throw new RuntimeException("No Ocean theme available");
}
pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS));
String prefix = System.getProperty("test.src",
System.getProperty("user.dir")) + System.getProperty("file.separator");
ImageIcon icon = new ImageIcon(prefix + "duke.gif");
JPanel panel = new JPanel();
JButton b = new JButton(icon);
b.setEnabled(false);
JLabel label = new JLabel(icon, SwingConstants.LEFT);
label.setEnabled(false);
JTabbedPane tp = new JTabbedPane();
tp.addTab("", icon, new JPanel());
tp.addTab("", icon, new JPanel());
tp.setEnabledAt(0, false);
tp.setEnabledAt(1, false);
JButton sb = new JButton(icon);
sb.setSelectedIcon(icon);
sb.setSelected(true);
sb.setEnabled(false);
JToggleButton tb = new JToggleButton(icon);
tb.setEnabled(false);
JToggleButton stb = new JToggleButton(icon);
stb.setSelectedIcon(icon);
stb.setSelected(true);
stb.setEnabled(false);
pane.setBackground(Color.white);
panel.setBackground(Color.white);
b.setBackground(Color.white);
label.setBackground(Color.white);
tp.setBackground(Color.white);
sb.setBackground(Color.white);
tb.setBackground(Color.white);
stb.setBackground(Color.white);
panel.add(b);
panel.add(label);
panel.add(tp);
panel.add(sb);
panel.add(tb);
panel.add(stb);
pane.add(panel);
pane.add(lfswitch);
frame.setSize(400, 400);
return frame;
}
static class LFSwitch extends JPanel {
private Component target;
static MetalTheme oceanTheme;
JComboBox lfcombo;
public LFSwitch(Component target) {
this.target = target;
setLayout(new FlowLayout());
lfcombo = new JComboBox(lookAndFeels);
add(lfcombo);
JButton setLfBut = new JButton("Set");
add(setLfBut);
setLfBut.addActionListener(e -> setLf(lfcombo.getSelectedIndex(),
LFSwitch.this.target));
}
boolean obtainOceanTheme() {
if (oceanTheme != null) {
return true;
}
try {
UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel");
SwingUtilities.updateComponentTreeUI(this);
} catch (Exception e) {
JOptionPane.showMessageDialog(this,
"Unexpected error: couldn't set Metal", "Error",
JOptionPane.ERROR_MESSAGE);
return false;
}
MetalTheme theme = (MetalTheme) AppContext.getAppContext().
get("currentMetalTheme");
if (theme == null || theme.getName() != "Ocean") {
JOptionPane.showMessageDialog(this,
"The Ocean theme is not the default Metal theme,\n" +
"but this test requires it to be default.\n" +
"Therefore simply click PASS");
return false;
}
oceanTheme = theme;
return true;
}
void setLf(int idx, final Component root) {
try {
UIManager.setLookAndFeel((LookAndFeel) lfs[idx]);
if (root != null) {
SwingUtilities.updateComponentTreeUI(root);
}
} catch (UnsupportedLookAndFeelException e) {
JOptionPane.showMessageDialog(root,
"The selected look and feel is unsupported on this platform",
"Error", JOptionPane.ERROR_MESSAGE);
} catch (Exception exc) {
JOptionPane.showMessageDialog(root,
"Error setting the selected look and feel", "Error",
JOptionPane.ERROR_MESSAGE);
}
}
static Object[] lookAndFeels = {
"Metal (Ocean)", "Metal (DefaultMetalTheme)",
};
static Object[] lfs = {
new MetalLookAndFeel() {
protected void createDefaultTheme() {
setCurrentTheme(oceanTheme);
}
},
new MetalLookAndFeel() {
protected void createDefaultTheme() {
MetalTheme dt = new DefaultMetalTheme();
setCurrentTheme(dt);
}
},
};
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,7 @@
@bug 6990651
@summary Regression: NPE when refreshing embedded window since 6u22-b01
@author Pavel Porvatov
@modules java.desktop/sun.awt
*/
import sun.awt.SunToolkit;
import javax.swing.*;
@ -43,7 +41,6 @@ public class bug6990651 {
Thread thread = new Thread(new ThreadGroup("Some ThreadGroup"), new Runnable() {
public void run() {
SunToolkit.createNewAppContext();
try {
SwingUtilities.invokeAndWait(new Runnable() {

View File

@ -1,101 +0,0 @@
/*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8019623
* @summary Tests that AppContext.getAppContext() works correctly in multi-threads scenario.
* @author Leonid Romanov
* @modules java.desktop/sun.awt
*/
import sun.awt.AppContext;
public class MultiThreadTest {
private static final int NUM_THREADS = 2;
private static AppContextGetter[] getters = new AppContextGetter[NUM_THREADS];
public static void main(String[] args) {
createAndStartThreads();
compareAppContexts();
}
private static void createAndStartThreads() {
ThreadGroup systemGroup = getSystemThreadGroup();
for (int i = 0; i < NUM_THREADS; ++i) {
ThreadGroup tg = new ThreadGroup(systemGroup, "AppContextGetter" + i);
getters[i] = new AppContextGetter(tg);
}
for (int i = 0; i < NUM_THREADS; ++i) {
getters[i].start();
}
for (int i = 0; i < NUM_THREADS; ++i) {
try {
getters[i].join();
} catch (InterruptedException e) {
// ignore
}
}
}
private static ThreadGroup getSystemThreadGroup() {
ThreadGroup currentThreadGroup =
Thread.currentThread().getThreadGroup();
ThreadGroup parentThreadGroup = currentThreadGroup.getParent();
while (parentThreadGroup != null) {
currentThreadGroup = parentThreadGroup;
parentThreadGroup = currentThreadGroup.getParent();
}
return currentThreadGroup;
}
private static void compareAppContexts() {
AppContext ctx = getters[0].getAppContext();
for (int i = 1; i < NUM_THREADS; ++i) {
if (!ctx.equals(getters[i].getAppContext())) {
throw new RuntimeException("Unexpected AppContexts difference, could be a race condition");
}
}
}
private static class AppContextGetter extends Thread {
private AppContext appContext;
public AppContextGetter(ThreadGroup tg) {
super(tg, tg.getName());
}
AppContext getAppContext() {
return appContext;
}
@Override
public void run() {
appContext = AppContext.getAppContext();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@
* @run main/othervm ClassLoaderLeakTest FontManagerTest
*/
import java.awt.Toolkit;
import java.awt.Font;
import java.awt.Graphics;
import java.io.File;
@ -48,6 +49,7 @@ public class ClassLoaderLeakTest {
private static Throwable launchFailure = null;
public static void main(String[] args) {
Toolkit.getDefaultToolkit().getSystemEventQueue(); // load EQ in initial TG
doneSignal = new CountDownLatch(1);
launchSignal = new CountDownLatch(1);