| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Oleg V. Khaschansky |
| * @version $Revision$ |
| */ |
| /* |
| * Created on 18.01.2005 |
| */ |
| package org.apache.harmony.awt.gl.image; |
| |
| import java.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| /** |
| * This class provides functionality for simultaneous loading of |
| * several images and running animation. |
| */ |
| public class ImageLoader extends Thread { |
| // Contains ImageLoader objects |
| // and queue of image sources waiting to be loaded |
| static class ImageLoadersStorage { |
| private static final int MAX_THREADS = 5; |
| private static final int TIMEOUT = 4000; |
| static ImageLoadersStorage instance; |
| |
| List<DecodingImageSource> queue = new LinkedList<DecodingImageSource>(); |
| List<Thread> loaders = new ArrayList<Thread>(MAX_THREADS); |
| |
| private int freeLoaders; |
| |
| private ImageLoadersStorage() {} |
| |
| static ImageLoadersStorage getStorage() { |
| if (instance == null) { |
| instance = new ImageLoadersStorage(); |
| } |
| |
| return instance; |
| } |
| } |
| |
| ImageLoader() { |
| super(); |
| setDaemon(true); |
| } |
| |
| /** |
| * This method creates a new thread which is able to load an image |
| * or run animation (if the number of existing loader threads does not |
| * exceed the limit). |
| */ |
| private static void createLoader() { |
| final ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| |
| synchronized(storage.loaders) { |
| if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) { |
| AccessController.doPrivileged( |
| new PrivilegedAction<Void>() { |
| public Void run() { |
| ImageLoader loader = new ImageLoader(); |
| storage.loaders.add(loader); |
| loader.start(); |
| return null; |
| } |
| }); |
| } |
| } |
| } |
| |
| /** |
| * Adds a new image source to the queue and starts a new loader |
| * thread if required |
| * @param imgSrc - image source |
| */ |
| public static void addImageSource(DecodingImageSource imgSrc) { |
| ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| synchronized(storage.queue) { |
| if (!storage.queue.contains(imgSrc)) { |
| storage.queue.add(imgSrc); |
| } |
| if (storage.freeLoaders == 0) { |
| createLoader(); |
| } |
| |
| storage.queue.notify(); |
| } |
| } |
| |
| /** |
| * Waits for a new ImageSource until timout expires. |
| * Loader thread will terminate after returning from this method |
| * if timeout expired and image source was not picked up from the queue. |
| * @return image source picked up from the queue or null if timeout expired |
| */ |
| private static DecodingImageSource getWaitingImageSource() { |
| ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| |
| synchronized(storage.queue) { |
| DecodingImageSource isrc = null; |
| |
| if (storage.queue.size() == 0) { |
| try { |
| storage.freeLoaders++; |
| storage.queue.wait(ImageLoadersStorage.TIMEOUT); |
| } catch (InterruptedException e) { |
| return null; |
| } finally { |
| storage.freeLoaders--; |
| } |
| } |
| |
| if (storage.queue.size() > 0) { |
| isrc = storage.queue.get(0); |
| storage.queue.remove(0); |
| } |
| |
| return isrc; |
| } |
| } |
| |
| /** |
| * Entry point of the loader thread. Picks up image sources and |
| * runs decoders for them while there are available image sources in the queue. |
| * If there are no and timeout expires it terminates. |
| */ |
| @Override |
| public void run() { |
| ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| |
| try { |
| while (storage.loaders.contains(this)) { |
| Thread.interrupted(); // Reset the interrupted flag |
| DecodingImageSource isrc = getWaitingImageSource(); |
| if (isrc != null) { |
| try { |
| isrc.load(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } else { |
| break; // Don't wait if timeout expired - terminate loader |
| } |
| } |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } finally { |
| synchronized(storage.loaders) { |
| storage.loaders.remove(Thread.currentThread()); |
| } |
| } |
| } |
| |
| /** |
| * Removes current thread from loaders (so we are able |
| * to create more loaders) and decreases its priority. |
| */ |
| static void beginAnimation() { |
| ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| Thread currThread = Thread.currentThread(); |
| |
| synchronized(storage) { |
| storage.loaders.remove(currThread); |
| |
| if (storage.freeLoaders < storage.queue.size()) { |
| createLoader(); |
| } |
| } |
| |
| currThread.setPriority(Thread.MIN_PRIORITY); |
| } |
| |
| /** |
| * Sends the current thread to wait for the new images to load |
| * if there are free placeholders for loaders |
| */ |
| static void endAnimation() { |
| ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); |
| Thread currThread = Thread.currentThread(); |
| |
| synchronized(storage) { |
| if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS && |
| !storage.loaders.contains(currThread) |
| ) { |
| storage.loaders.add(currThread); |
| } |
| } |
| |
| currThread.setPriority(Thread.NORM_PRIORITY); |
| } |
| } |