001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.cache; 003 004import java.awt.image.BufferedImage; 005import java.io.ByteArrayInputStream; 006import java.io.IOException; 007 008import javax.imageio.ImageIO; 009 010/** 011 * Cache Entry that has methods to get the BufferedImage, that will be cached along in memory 012 * but will be not serialized when saved to the disk (to avoid duplication of data) 013 * @author Wiktor Niesiobędzki 014 * 015 */ 016public class BufferedImageCacheEntry extends CacheEntry { 017 private static final long serialVersionUID = 1L; //version 018 // transient to avoid serialization, volatile to avoid synchronization of whole getImage() method 019 private transient volatile BufferedImage img; 020 private transient volatile boolean writtenToDisk; 021 // we need to have separate control variable, to know, if we already tried to load the image, as img might be null 022 // after we loaded image, as for example, when image file is malformed (eg. HTML file) 023 private transient volatile boolean imageLoaded; 024 025 /** 026 * 027 * @param content byte array containing image 028 */ 029 public BufferedImageCacheEntry(byte[] content) { 030 super(content); 031 } 032 033 /** 034 * Returns BufferedImage from for the content. Subsequent calls will return the same instance, 035 * to reduce overhead of ImageIO 036 * 037 * @return BufferedImage of cache entry content 038 * @throws IOException if an error occurs during reading. 039 */ 040 public BufferedImage getImage() throws IOException { 041 if (imageLoaded) 042 return img; 043 synchronized (this) { 044 if (imageLoaded) 045 return img; 046 byte[] content = getContent(); 047 if (content != null && content.length > 0) { 048 img = ImageIO.read(new ByteArrayInputStream(content)); 049 imageLoaded = true; 050 } 051 } 052 return img; 053 } 054 055 private void writeObject(java.io.ObjectOutputStream out) throws IOException { 056 /* 057 * This method below will be needed, if Apache Commons JCS (or any other caching system), will update 058 * disk representation of object from memory, once it is put into the cache (for example - at closing the cache) 059 * 060 * For now it is not the case, as we use DiskUsagePattern.UPDATE, which on JCS shutdown doesn't write again memory 061 * contents to file, so the fact, that we've cleared never gets saved to the disk 062 * 063 * This method is commented out, as it will convert all cache entries to PNG files regardless of what was returned. 064 * It might cause recompression/change of format which may result in decreased quality of imagery 065 */ 066 /* synchronized (this) { 067 if (content == null && img != null) { 068 ByteArrayOutputStream restoredData = new ByteArrayOutputStream(); 069 ImageIO.write(img, "png", restoredData); 070 content = restoredData.toByteArray(); 071 } 072 out.writeObject(this); 073 } 074 */ 075 synchronized (this) { 076 if (content == null && img != null) { 077 throw new AssertionError("Trying to serialize (save to disk?) an BufferedImageCacheEntry " + 078 "that was converted to BufferedImage and no raw data is present anymore"); 079 } 080 out.writeObject(this); 081 // ugly hack to wait till element will get to disk to clean the memory 082 writtenToDisk = true; 083 084 if (img != null) { 085 content = null; 086 } 087 } 088 } 089}