001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.springframework.richclient.image; 017 018 import java.awt.Image; 019 import java.io.IOException; 020 import java.util.HashMap; 021 import java.util.Map; 022 023 import org.apache.commons.logging.Log; 024 import org.apache.commons.logging.LogFactory; 025 import org.springframework.core.io.Resource; 026 import org.springframework.core.style.StylerUtils; 027 import org.springframework.core.style.ToStringCreator; 028 import org.springframework.util.Assert; 029 import org.springframework.util.CachingMapDecorator; 030 031 /** 032 * A collection of image resources, each indexed by a common key alias. 033 * <p> 034 * For example, <code>action.edit.copy = /images/edit/copy.gif</code> 035 * <p> 036 * This class by default performs caching of all loaded image resources using 037 * soft references (TODO it just lazy loads them, but it doesn't use 038 * SoftReference). 039 * 040 * <p> 041 * An image {@link Handler} is available that handles the 'image' protocol. 042 * Check the javadocs of the handler to know how to use/register it. 043 * </p> 044 * 045 * @author Keith Donald 046 */ 047 public class DefaultImageSource implements ImageSource { 048 protected static final Log logger = LogFactory.getLog(DefaultImageSource.class); 049 050 private Map imageResources; 051 052 private ImageCache imageCache; 053 054 private AwtImageResource brokenImageIndicatorResource; 055 056 private Image brokenImageIndicator; 057 058 /** 059 * Creates a image resource bundle containing the specified map of keys to 060 * resource paths. 061 * <p> 062 * A custom URL protocol {@link Handler handler}will be installed for the 063 * "image:" protocol. This allows for images in this image source to be 064 * located using the Java URL classes: <br> 065 * <code>URL imageUrl = new URL("image:the.image.key")</code> 066 * 067 * @param imageResources a map of key-to-image-resources. 068 */ 069 public DefaultImageSource(Map imageResources) { 070 this(true, imageResources); 071 } 072 073 /** 074 * Creates a image resource bundle containing the specified map of keys to 075 * resource paths. 076 * 077 * @param installUrlHandler should a URL handler be installed. 078 * @param imageResources a map of key-to-image-resources. 079 */ 080 public DefaultImageSource(boolean installUrlHandler, Map imageResources) { 081 Assert.notNull(imageResources); 082 this.imageResources = new HashMap(imageResources); 083 debugPrintResources(); 084 this.imageCache = new ImageCache(); 085 if (installUrlHandler) { 086 Handler.installImageUrlHandler(this); 087 } 088 } 089 090 private void debugPrintResources() { 091 if (logger.isDebugEnabled()) { 092 logger.debug("Initialing image source with resources: " + StylerUtils.style(this.imageResources)); 093 } 094 } 095 096 public Image getImage(String key) { 097 Assert.notNull(key); 098 AwtImageResource resource = getImageResource(key); 099 try { 100 return (Image) imageCache.get(resource); 101 } 102 catch (RuntimeException e) { 103 if (brokenImageIndicator != null) { 104 return returnBrokenImageIndicator(resource); 105 } 106 throw e; 107 } 108 } 109 110 public AwtImageResource getImageResource(String key) { 111 Assert.notNull(key); 112 Resource resource = (Resource) imageResources.get(key); 113 if (resource == null) { 114 throw new NoSuchImageResourceException(key); 115 } 116 try { 117 resource.getInputStream(); 118 return new AwtImageResource(resource); 119 } 120 catch (IOException e) { 121 if (brokenImageIndicatorResource == null) { 122 throw new NoSuchImageResourceException(resource, e); 123 } 124 logger.warn("Unable to load image resource at '" + resource + "'; returning the broken image indicator."); 125 return brokenImageIndicatorResource; 126 } 127 } 128 129 public boolean containsKey(Object key) { 130 return imageResources.containsKey(key); 131 } 132 133 private Image returnBrokenImageIndicator(Resource resource) { 134 logger.warn("Unable to load image resource at '" + resource + "'; returning the broken image indicator."); 135 return brokenImageIndicator; 136 } 137 138 public Image getImageAtLocation(Resource location) { 139 try { 140 return new AwtImageResource(location).getImage(); 141 } 142 catch (IOException e) { 143 if (brokenImageIndicator == null) { 144 throw new NoSuchImageResourceException(location, e); 145 } 146 return returnBrokenImageIndicator(location); 147 } 148 } 149 150 public int size() { 151 return imageResources.size(); 152 } 153 154 public void setBrokenImageIndicator(Resource resource) { 155 try { 156 brokenImageIndicatorResource = new AwtImageResource(resource); 157 brokenImageIndicator = brokenImageIndicatorResource.getImage(); 158 } 159 catch (IOException e) { 160 brokenImageIndicatorResource = null; 161 throw new NoSuchImageResourceException(resource, e); 162 } 163 } 164 165 public String toString() { 166 return new ToStringCreator(this).append("imageResources", imageResources).toString(); 167 } 168 169 private static class ImageCache extends CachingMapDecorator { 170 public ImageCache() { 171 super(true); 172 } 173 174 public Object create(Object resource) { 175 try { 176 return ((AwtImageResource) resource).getImage(); 177 } 178 catch (IOException e) { 179 throw new NoSuchImageResourceException("No image found at resource '" + resource + '"', e); 180 } 181 } 182 } 183 }