Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id: SoftMapCache.java 750418 2009-03-05 11:03:54Z vhennebert $ */ package org.apache.xmlgraphics.image.loader.util; import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.util.Collections; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Provides a simple cache using soft references and storing the values in a Map. The keys into * the Map are hard references, the values are referenced through soft references. The collected * values are cleaned up through a ReferenceQueue. */ public class SoftMapCache { /** logger */ private static Log log = LogFactory.getLog(SoftMapCache.class); private Map map; private ReferenceQueue refQueue = new ReferenceQueue(); /** * Creates a new soft cache. * @param synched true if the Map containing the values should by synchronized */ public SoftMapCache(boolean synched) { this.map = new java.util.HashMap(); if (synched) { this.map = Collections.synchronizedMap(this.map); } } /** * Returns the value associated with the given key. If the value is not found or the value * has been collected, null is returned. * @param key the key * @return the requested value or null */ public Object get(Object key) { Reference ref = (Reference) map.get(key); return getReference(key, ref); } /** * Removed the value associated with the given key. The value that is removed is returned * as the methods result. If the value is not found or the value has been collected, * null is returned. * @param key the key * @return the requested value or null */ public Object remove(Object key) { Reference ref = (Reference) map.remove(key); return getReference(key, ref); } private Object getReference(Object key, Reference ref) { Object value = null; if (ref != null) { value = ref.get(); if (value == null) { //Remove key if its value has been garbage collected if (log.isTraceEnabled()) { log.trace("Image has been collected: " + key); } checkReferenceQueue(); } } return value; } /** * Put a new value in the cache overwriting any existing value with the same key. * @param key The key * @param value the value */ public void put(Object key, Object value) { map.put(key, wrapInReference(value, key)); } /** * Clears the cache. */ public void clear() { map.clear(); } /** * Triggers some house-keeping, i.e. processes any pending objects in the reference queue. */ public void doHouseKeeping() { checkReferenceQueue(); } private Reference wrapInReference(Object obj, Object key) { return new SoftReferenceWithKey(obj, key, refQueue); } /** * Checks the reference queue if any references have been cleared and removes them from the * cache. */ private void checkReferenceQueue() { SoftReferenceWithKey ref; while ((ref = (SoftReferenceWithKey) refQueue.poll()) != null) { if (log.isTraceEnabled()) { log.trace("Removing ImageInfo from ref queue: " + ref.getKey()); } map.remove(ref.getKey()); } } }