1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17/** 18 * @author Oleg V. Khaschansky 19 * @version $Revision$ 20 */ 21/* 22 * Created on 18.01.2005 23 */ 24package org.apache.harmony.awt.gl.image; 25 26import java.security.AccessController; 27import java.security.PrivilegedAction; 28import java.util.ArrayList; 29import java.util.LinkedList; 30import java.util.List; 31 32/** 33 * This class provides functionality for simultaneous loading of 34 * several images and running animation. 35 */ 36public class ImageLoader extends Thread { 37 // Contains ImageLoader objects 38 // and queue of image sources waiting to be loaded 39 static class ImageLoadersStorage { 40 private static final int MAX_THREADS = 5; 41 private static final int TIMEOUT = 4000; 42 static ImageLoadersStorage instance; 43 44 List<DecodingImageSource> queue = new LinkedList<DecodingImageSource>(); 45 List<Thread> loaders = new ArrayList<Thread>(MAX_THREADS); 46 47 private int freeLoaders; 48 49 private ImageLoadersStorage() {} 50 51 static ImageLoadersStorage getStorage() { 52 if (instance == null) { 53 instance = new ImageLoadersStorage(); 54 } 55 56 return instance; 57 } 58 } 59 60 ImageLoader() { 61 super(); 62 setDaemon(true); 63 } 64 65 /** 66 * This method creates a new thread which is able to load an image 67 * or run animation (if the number of existing loader threads does not 68 * exceed the limit). 69 */ 70 private static void createLoader() { 71 final ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 72 73 synchronized(storage.loaders) { 74 if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS) { 75 AccessController.doPrivileged( 76 new PrivilegedAction<Void>() { 77 public Void run() { 78 ImageLoader loader = new ImageLoader(); 79 storage.loaders.add(loader); 80 loader.start(); 81 return null; 82 } 83 }); 84 } 85 } 86 } 87 88 /** 89 * Adds a new image source to the queue and starts a new loader 90 * thread if required 91 * @param imgSrc - image source 92 */ 93 public static void addImageSource(DecodingImageSource imgSrc) { 94 ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 95 synchronized(storage.queue) { 96 if (!storage.queue.contains(imgSrc)) { 97 storage.queue.add(imgSrc); 98 } 99 if (storage.freeLoaders == 0) { 100 createLoader(); 101 } 102 103 storage.queue.notify(); 104 } 105 } 106 107 /** 108 * Waits for a new ImageSource until timout expires. 109 * Loader thread will terminate after returning from this method 110 * if timeout expired and image source was not picked up from the queue. 111 * @return image source picked up from the queue or null if timeout expired 112 */ 113 private static DecodingImageSource getWaitingImageSource() { 114 ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 115 116 synchronized(storage.queue) { 117 DecodingImageSource isrc = null; 118 119 if (storage.queue.size() == 0) { 120 try { 121 storage.freeLoaders++; 122 storage.queue.wait(ImageLoadersStorage.TIMEOUT); 123 } catch (InterruptedException e) { 124 return null; 125 } finally { 126 storage.freeLoaders--; 127 } 128 } 129 130 if (storage.queue.size() > 0) { 131 isrc = storage.queue.get(0); 132 storage.queue.remove(0); 133 } 134 135 return isrc; 136 } 137 } 138 139 /** 140 * Entry point of the loader thread. Picks up image sources and 141 * runs decoders for them while there are available image sources in the queue. 142 * If there are no and timeout expires it terminates. 143 */ 144 @Override 145 public void run() { 146 ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 147 148 try { 149 while (storage.loaders.contains(this)) { 150 Thread.interrupted(); // Reset the interrupted flag 151 DecodingImageSource isrc = getWaitingImageSource(); 152 if (isrc != null) { 153 try { 154 isrc.load(); 155 } catch (Exception e) { 156 e.printStackTrace(); 157 } 158 } else { 159 break; // Don't wait if timeout expired - terminate loader 160 } 161 } 162 } catch (Exception e) { 163 e.printStackTrace(); 164 } finally { 165 synchronized(storage.loaders) { 166 storage.loaders.remove(Thread.currentThread()); 167 } 168 } 169 } 170 171 /** 172 * Removes current thread from loaders (so we are able 173 * to create more loaders) and decreases its priority. 174 */ 175 static void beginAnimation() { 176 ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 177 Thread currThread = Thread.currentThread(); 178 179 synchronized(storage) { 180 storage.loaders.remove(currThread); 181 182 if (storage.freeLoaders < storage.queue.size()) { 183 createLoader(); 184 } 185 } 186 187 currThread.setPriority(Thread.MIN_PRIORITY); 188 } 189 190 /** 191 * Sends the current thread to wait for the new images to load 192 * if there are free placeholders for loaders 193 */ 194 static void endAnimation() { 195 ImageLoadersStorage storage = ImageLoadersStorage.getStorage(); 196 Thread currThread = Thread.currentThread(); 197 198 synchronized(storage) { 199 if (storage.loaders.size() < ImageLoadersStorage.MAX_THREADS && 200 !storage.loaders.contains(currThread) 201 ) { 202 storage.loaders.add(currThread); 203 } 204 } 205 206 currThread.setPriority(Thread.NORM_PRIORITY); 207 } 208}