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 if (writtenToDisk) 052 content = null; 053 } 054 055 } 056 return img; 057 } 058 059 private void writeObject(java.io.ObjectOutputStream out) throws IOException { 060 /* 061 * This method below will be needed, if Apache Commons JCS (or any other caching system), will update 062 * disk representation of object from memory, once it is put into the cache (for example - at closing the cache) 063 * 064 * For now it is not the case, as we use DiskUsagePattern.UPDATE, which on JCS shutdown doesn't write again memory 065 * contents to file, so the fact, that we've cleared never gets saved to the disk 066 * 067 * This method is commented out, as it will convert all cache entries to PNG files regardless of what was returned. 068 * It might cause recompression/change of format which may result in decreased quality of imagery 069 */ 070 /* synchronized (this) { 071 if (content == null && img != null) { 072 ByteArrayOutputStream restoredData = new ByteArrayOutputStream(); 073 ImageIO.write(img, "png", restoredData); 074 content = restoredData.toByteArray(); 075 } 076 out.writeObject(this); 077 } 078 */ 079 synchronized (this) { 080 if (content == null && img != null) { 081 throw new AssertionError("Trying to serialize (save to disk?) an BufferedImageCacheEntry " + 082 "that was converted to BufferedImage and no raw data is present anymore"); 083 } 084 out.writeObject(this); 085 // ugly hack to wait till element will get to disk to clean the memory 086 writtenToDisk = true; 087 088 if (img != null) { 089 content = null; 090 } 091 } 092 } 093}