/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package com.bc.ceres.jai.tilecache; import javax.media.jai.CachedTile; import java.awt.image.DataBuffer; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.Image; import java.lang.ref.WeakReference; import java.math.BigInteger; /** * Information associated with a cached tile. * <p/> * <p> This class is used by {@link SwappingTileCache} to create an object that * includes all the information associated with a tile, and is put * into the tile cache. * <p/> * The implementation is based on the Sun Microsystems' implementation of * the <code>javax.media.jai.CachedTile</code> interface. * * @author Sun Microsystems * @author Norman Fomferra */ public final class MemoryTile implements CachedTile { // Soft or Weak references need to be used, or the objects // never get garbage collected. The OpImage finalize // method calls removeTiles(). It was suggested, that // the owner be a weak reference. Raster tile; // the tile to be cached WeakReference owner; // the RenderedImage this tile belongs to int tileX; // tile X index int tileY; // tile Y index Object tileCacheMetric; // Metric for weighting tile computation cost long timeStamp; // the last time this tile is accessed Object key; // the key used to hash this tile long tileSize; // the memory used by this tile in bytes MemoryTile previous; // the SunCachedTile before this tile MemoryTile next; // the SunCachedTile after this tile int action = 0; // add, remove, update from tile cache MemoryTile(RenderedImage owner, int tileX, int tileY, Raster tile, Object tileCacheMetric) { this.owner = new WeakReference<RenderedImage>(owner); this.tile = tile; this.tileX = tileX; this.tileY = tileY; this.tileCacheMetric = tileCacheMetric; // may be null this.key = hashKey(owner, tileX, tileY); DataBuffer db = tile.getDataBuffer(); this.tileSize = DataBuffer.getDataTypeSize(db.getDataType()) / 8L * db.getSize() * db.getNumBanks(); } public int getTileX() { return tileX; } public int getTileY() { return tileY; } public Object getKey() { return key; } /* * Returns the hash table "key" as a <code>Object</code> for this * tile. For <code>PlanarImage</code> and * <code>SerializableRenderedImage</code>, the key is generated by * the method <code>ImageUtilgenerateID(Object) </code>. For the * other cases, a <code>Long</code> object is returned. * The upper 32 bits for this <code>Long</code> is the tile owner's * hash code, and the lower 32 bits is the tile's index. */ public static Object hashKey(RenderedImage owner, int tileX, int tileY) { // todo - added new (but unsafe) key for better readability (swapped file names) Object imageId = owner.getProperty("imageId"); if (imageId == null || Image.UndefinedProperty.equals(imageId)) { return Integer.toHexString(owner.hashCode()) + "_" + tileX + "_" + tileY + "_" + owner.getClass().getName().replace('.', '_'); } else { return Integer.toHexString(owner.hashCode()) + "_" + tileX + "_" + tileY + "_" + imageId; } // todo - restore original Sun code /* long idx = tileY * (long) owner.getNumXTiles() + tileX; BigInteger imageID = null; if (owner instanceof PlanarImage) imageID = (BigInteger) ((PlanarImage) owner).getImageID(); else if (owner instanceof SerializableRenderedImage) imageID = (BigInteger) ((SerializableRenderedImage) owner).getImageID(); if (imageID != null) { byte[] buf = imageID.toByteArray(); int length = buf.length; byte[] buf1 = new byte[length + 8]; System.arraycopy(buf, 0, buf1, 0, length); for (int i = 7, j = 0; i >= 0; i--, j += 8) buf1[length++] = (byte) (idx >> j); return new BigInteger(buf1); } idx = idx & 0x00000000ffffffffL; return ((long) owner.hashCode() << 32) | idx; */ } /** * Special version of hashKey for use in SunTileCache.removeTiles(). * Minimizes the overhead of repeated calls to * hashCode and getNumTiles(). Note that this causes a * linkage between the CachedTile and SunTileCache classes * in that SunTileCache now has to understand how the * tileIndex is calculated. */ /* static Long hashKey(int ownerHashCode, int tileIndex) { long idx = (long)tileIndex; idx = idx & 0x00000000ffffffffL; return new Long(((long)ownerHashCode << 32) | idx); } */ /** Returns the owner's hash code. */ /* static long getOwnerHashCode(Long key) { return key.longValue() >>> 32; } */ /** * Returns a string representation of the class object. */ public String toString() { RenderedImage o = getOwner(); String ostring = o == null ? "null" : o.toString(); Raster t = getTile(); String tstring = t == null ? "null" : t.toString(); return getClass().getName() + "@" + Integer.toHexString(hashCode()) + ": owner = " + ostring + " tileX = " + Integer.toString(tileX) + " tileY = " + Integer.toString(tileY) + " tile = " + tstring + " key = " + getKeyAsString() + " tileSize = " + Long.toString(tileSize) + " timeStamp = " + Long.toString(timeStamp); } public String getKeyAsString() { if (key instanceof BigInteger) { BigInteger bigInteger = (BigInteger) key; return bigInteger.toString(16); } return ((key instanceof Long) ? Long.toHexString((Long) key) : key.toString()); } /** * Returns the cached tile. */ public Raster getTile() { return tile; } /** * Returns the owner of the cached tile. */ public RenderedImage getOwner() { return (RenderedImage) owner.get(); } /** * Returns the current time stamp */ public long getTileTimeStamp() { return timeStamp; } /** * Returns the tileCacheMetric object */ public Object getTileCacheMetric() { return tileCacheMetric; } /** * Returns the tile memory size */ public long getTileSize() { return tileSize; } /** * Returns information about the method that * triggered the notification event. */ public int getAction() { return action; } }