|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package sun.awt.image; |
|
|
|
import java.util.Vector; |
|
import sun.awt.AppContext; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class ImageFetcher extends Thread { |
|
static final int HIGH_PRIORITY = 8; |
|
static final int LOW_PRIORITY = 3; |
|
static final int ANIM_PRIORITY = 2; |
|
|
|
static final int TIMEOUT = 5000; |
|
// ImageFetchable to be added to the |
|
// queue before an ImageFetcher dies |
|
|
|
|
|
|
|
*/ |
|
private ImageFetcher(ThreadGroup threadGroup, int index) { |
|
super(threadGroup, "Image Fetcher " + index); |
|
setDaemon(true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
public static boolean add(ImageFetchable src) { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
synchronized(info.waitList) { |
|
if (!info.waitList.contains(src)) { |
|
info.waitList.addElement(src); |
|
if (info.numWaiting == 0 && |
|
info.numFetchers < info.fetchers.length) { |
|
createFetchers(info); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
if (info.numFetchers > 0) { |
|
info.waitList.notify(); |
|
} else { |
|
info.waitList.removeElement(src); |
|
return false; |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static void remove(ImageFetchable src) { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
synchronized(info.waitList) { |
|
if (info.waitList.contains(src)) { |
|
info.waitList.removeElement(src); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static boolean isFetcher(Thread t) { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
synchronized(info.waitList) { |
|
for (int i = 0; i < info.fetchers.length; i++) { |
|
if (info.fetchers[i] == t) { |
|
return true; |
|
} |
|
} |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
*/ |
|
public static boolean amFetcher() { |
|
return isFetcher(Thread.currentThread()); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static ImageFetchable nextImage() { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
synchronized(info.waitList) { |
|
ImageFetchable src = null; |
|
long end = System.currentTimeMillis() + TIMEOUT; |
|
while (src == null) { |
|
while (info.waitList.size() == 0) { |
|
long now = System.currentTimeMillis(); |
|
if (now >= end) { |
|
return null; |
|
} |
|
try { |
|
info.numWaiting++; |
|
info.waitList.wait(end - now); |
|
} catch (InterruptedException e) { |
|
|
|
return null; |
|
} finally { |
|
info.numWaiting--; |
|
} |
|
} |
|
src = (ImageFetchable) info.waitList.elementAt(0); |
|
info.waitList.removeElement(src); |
|
} |
|
return src; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
*/ |
|
public void run() { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
try { |
|
fetchloop(); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
} finally { |
|
synchronized(info.waitList) { |
|
Thread me = Thread.currentThread(); |
|
for (int i = 0; i < info.fetchers.length; i++) { |
|
if (info.fetchers[i] == me) { |
|
info.fetchers[i] = null; |
|
info.numFetchers--; |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private void fetchloop() { |
|
Thread me = Thread.currentThread(); |
|
while (isFetcher(me)) { |
|
// we're ignoring the return value and just clearing |
|
// the interrupted flag, instead of bailing out if |
|
// the fetcher was interrupted, as we used to, |
|
// because there may be other images waiting |
|
|
|
me.interrupted(); |
|
me.setPriority(HIGH_PRIORITY); |
|
ImageFetchable src = nextImage(); |
|
if (src == null) { |
|
return; |
|
} |
|
try { |
|
src.doFetch(); |
|
} catch (Exception e) { |
|
System.err.println("Uncaught error fetching image:"); |
|
e.printStackTrace(); |
|
} |
|
stoppingAnimation(me); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
static void startingAnimation() { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
Thread me = Thread.currentThread(); |
|
synchronized(info.waitList) { |
|
for (int i = 0; i < info.fetchers.length; i++) { |
|
if (info.fetchers[i] == me) { |
|
info.fetchers[i] = null; |
|
info.numFetchers--; |
|
me.setName("Image Animator " + i); |
|
if(info.waitList.size() > info.numWaiting) { |
|
createFetchers(info); |
|
} |
|
return; |
|
} |
|
} |
|
} |
|
me.setPriority(ANIM_PRIORITY); |
|
me.setName("Image Animator"); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
private static void stoppingAnimation(Thread me) { |
|
final FetcherInfo info = FetcherInfo.getFetcherInfo(); |
|
synchronized(info.waitList) { |
|
int index = -1; |
|
for (int i = 0; i < info.fetchers.length; i++) { |
|
if (info.fetchers[i] == me) { |
|
return; |
|
} |
|
if (info.fetchers[i] == null) { |
|
index = i; |
|
} |
|
} |
|
if (index >= 0) { |
|
info.fetchers[index] = me; |
|
info.numFetchers++; |
|
me.setName("Image Fetcher " + index); |
|
return; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
*/ |
|
private static void createFetchers(final FetcherInfo info) { |
|
// We need to instantiate a new ImageFetcher thread. |
|
// First, figure out which ThreadGroup we'll put the |
|
|
|
final AppContext appContext = AppContext.getAppContext(); |
|
ThreadGroup threadGroup = appContext.getThreadGroup(); |
|
ThreadGroup fetcherThreadGroup; |
|
try { |
|
if (threadGroup.getParent() != null) { |
|
|
|
fetcherThreadGroup = threadGroup; |
|
} else { |
|
// threadGroup is the root ("system") ThreadGroup. |
|
// We instead want to use its child: the "main" |
|
// ThreadGroup. Thus, we start with the current |
|
// ThreadGroup, and go up the tree until |
|
|
|
threadGroup = Thread.currentThread().getThreadGroup(); |
|
ThreadGroup parent = threadGroup.getParent(); |
|
while ((parent != null) |
|
&& (parent.getParent() != null)) { |
|
threadGroup = parent; |
|
parent = threadGroup.getParent(); |
|
} |
|
fetcherThreadGroup = threadGroup; |
|
} |
|
} catch (SecurityException e) { |
|
// Not allowed access to parent ThreadGroup -- just use |
|
|
|
fetcherThreadGroup = appContext.getThreadGroup(); |
|
} |
|
final ThreadGroup fetcherGroup = fetcherThreadGroup; |
|
|
|
java.security.AccessController.doPrivileged( |
|
new java.security.PrivilegedAction() { |
|
public Object run() { |
|
for (int i = 0; i < info.fetchers.length; i++) { |
|
if (info.fetchers[i] == null) { |
|
ImageFetcher f = new ImageFetcher( |
|
fetcherGroup, i); |
|
try { |
|
f.start(); |
|
info.fetchers[i] = f; |
|
info.numFetchers++; |
|
break; |
|
} catch (Error e) { |
|
} |
|
} |
|
} |
|
return null; |
|
} |
|
}); |
|
return; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
class FetcherInfo { |
|
static final int MAX_NUM_FETCHERS_PER_APPCONTEXT = 4; |
|
|
|
Thread[] fetchers; |
|
int numFetchers; |
|
int numWaiting; |
|
Vector waitList; |
|
|
|
private FetcherInfo() { |
|
fetchers = new Thread[MAX_NUM_FETCHERS_PER_APPCONTEXT]; |
|
numFetchers = 0; |
|
numWaiting = 0; |
|
waitList = new Vector(); |
|
} |
|
|
|
|
|
private static final Object FETCHER_INFO_KEY = |
|
new StringBuffer("FetcherInfo"); |
|
|
|
static FetcherInfo getFetcherInfo() { |
|
AppContext appContext = AppContext.getAppContext(); |
|
synchronized(appContext) { |
|
FetcherInfo info = (FetcherInfo)appContext.get(FETCHER_INFO_KEY); |
|
if (info == null) { |
|
info = new FetcherInfo(); |
|
appContext.put(FETCHER_INFO_KEY, info); |
|
} |
|
return info; |
|
} |
|
} |
|
} |