Package ae.sun.awt.image

Source Code of ae.sun.awt.image.ImageFetcher

/*
* Copyright 1995-2003 Sun Microsystems, Inc.  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.  Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/

package ae.sun.awt.image;

import java.util.Vector;

import ae.sun.awt.AppContext;

/**
  * An ImageFetcher is a thread used to fetch ImageFetchable objects.
  * Once an ImageFetchable object has been fetched, the ImageFetcher
  * thread may also be used to animate it if necessary, via the
  * startingAnimation() / stoppingAnimation() methods.
  *
  * There can be up to FetcherInfo.MAX_NUM_FETCHERS_PER_APPCONTEXT
  * ImageFetcher threads for each AppContext.  A per-AppContext queue
  * of ImageFetchables is used to track objects to fetch.
  *
  * @author Jim Graham
  * @author Fred Ecks
  */
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; // Time in milliseconds to wait for an
                                     // ImageFetchable to be added to the
                                     // queue before an ImageFetcher dies

    /**
      * Constructor for ImageFetcher -- only called by add() below.
      */
    private ImageFetcher(ThreadGroup threadGroup, int index) {
        super(threadGroup, "Image Fetcher " + index);
        setDaemon(true);
    }

    /**
      * Adds an ImageFetchable to the queue of items to fetch.  Instantiates
      * a new ImageFetcher if it's reasonable to do so.
      */
    public static void 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);
                }
                info.waitList.notify();
            }
        }
    }

    /**
      * Removes an ImageFetchable from the queue of items to fetch.
      */
    public static void remove(ImageFetchable src) {
        final FetcherInfo info = FetcherInfo.getFetcherInfo();
        synchronized(info.waitList) {
            if (info.waitList.contains(src)) {
                info.waitList.removeElement(src);
            }
        }
    }

    /**
      * Checks to see if the given thread is one of the ImageFetchers.
      */
    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;
    }

    /**
      * Checks to see if the current thread is one of the ImageFetchers.
      */
    public static boolean amFetcher() {
        return isFetcher(Thread.currentThread());
    }

    /**
      * Returns the next ImageFetchable to be processed.  If TIMEOUT
      * elapses in the mean time, or if the ImageFetcher is interrupted,
      * null is returned.
      */
    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) {
                        // A normal occurrence as an AppContext is disposed
                        return null;
                    } finally {
                        info.numWaiting--;
                    }
                }
                src = (ImageFetchable) info.waitList.elementAt(0);
                info.waitList.removeElement(src);
            }
            return src;
        }
    }

    /**
      * The main run() method of an ImageFetcher Thread.  Calls fetchloop()
      * to do the work, then removes itself from the array of ImageFetchers.
      */
    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--;
                    }
                }
            }
        }
    }

    /**
      * The main ImageFetcher loop.  Repeatedly calls nextImage(), and
      * fetches the returned ImageFetchable objects until nextImage()
      * returns null.
      */
    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
            // to be fetched (see 4789067)
            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);
        }
    }


    /**
      * Recycles this ImageFetcher thread as an image animator thread.
      * Removes this ImageFetcher from the array of ImageFetchers, and
      * resets the thread name to "ImageAnimator".
      */
    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");
    }

    /**
      * Returns this image animator thread back to service as an ImageFetcher
      * if possible.  Puts it back into the array of ImageFetchers and sets
      * the thread name back to "Image Fetcher".  If there are already the
      * maximum number of ImageFetchers, this method simply returns, and
      * fetchloop() will drop out when it sees that this thread isn't one of
      * the ImageFetchers, and this thread will die.
      */
    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;
            }
        }
    }

    /**
      * Create and start ImageFetcher threads in the appropriate ThreadGroup.
      */
    private static void createFetchers(final FetcherInfo info) {
       // We need to instantiate a new ImageFetcher thread.
       // First, figure out which ThreadGroup we'll put the
       // new ImageFetcher into
       final AppContext appContext = AppContext.getAppContext();
       ThreadGroup threadGroup = appContext.getThreadGroup();
       ThreadGroup fetcherThreadGroup;
       try {
          if (threadGroup.getParent() != null) {
             // threadGroup is not the root, so we proceed
             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.getParent().getParent() == null.
             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
         // the AppContext's ThreadGroup
         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) {
                   info.fetchers[i] = new ImageFetcher(
                           fetcherGroup, i);
                   info.fetchers[i].start();
                   info.numFetchers++;
                   break;
               }
             }
          return null;
        }
       });
      return;
    }

}

/**
  * The FetcherInfo class encapsulates the per-AppContext ImageFetcher
  * information.  This includes the array of ImageFetchers, as well as
  * the queue of ImageFetchable objects.
  */
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();
    }

    /* The key to put()/get() the FetcherInfo into/from the AppContext. */
    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;
        }
    }
}
TOP

Related Classes of ae.sun.awt.image.ImageFetcher

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.