| /* |
| * 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$ */ |
| |
| 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()); |
| } |
| } |
| } |