001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.util; 018 019import java.lang.ref.WeakReference; 020import java.util.HashMap; 021import java.util.Iterator; 022 023/** 024 * Extends a {@link HashMap} with {@link WeakReference} values, so that 025 * weak references which have been cleared are periodically removed from 026 * the map. The cleaning occurs as part of {@link #put}, after a specific 027 * number ({@link #cleanInterval}) of calls to {@link #put}. 028 * 029 * @param <K> The key type. 030 * @param <V> The value type. 031 * 032 * @author Boris Grozev 033 */ 034public class CleaningWeakReferenceMap<K, V> 035 extends HashMap<K, WeakReference<V>> { 036 private static final long serialVersionUID = 0L; 037 038 /** 039 * The number of calls to {@link #put} after which to clean this map 040 * (i.e. remove cleared {@link WeakReference}s from it). 041 */ 042 private final int cleanInterval; 043 044 /** 045 * The number of times {@link #put} has been called on this instance 046 * since the last time it was {@link #clean}ed. 047 */ 048 private int numberOfInsertsSinceLastClean = 0; 049 050 /** 051 * Initializes a new {@link CleaningWeakReferenceMap} instance with the 052 * default clean interval. 053 */ 054 public CleaningWeakReferenceMap() { 055 this(50); 056 } 057 058 /** 059 * Initializes a new {@link CleaningWeakReferenceMap} instance with a given 060 * clean interval. 061 * @param cleanInterval the number of calls to {@link #put} after which the 062 * map will clean itself. 063 */ 064 public CleaningWeakReferenceMap(int cleanInterval) { 065 this.cleanInterval = cleanInterval; 066 } 067 068 @Override 069 public WeakReference<V> put(K key, WeakReference<V> value) { 070 WeakReference<V> ret = super.put(key, value); 071 072 if (numberOfInsertsSinceLastClean++ > cleanInterval) { 073 numberOfInsertsSinceLastClean = 0; 074 clean(); 075 } 076 077 return ret; 078 } 079 080 /** 081 * Removes all cleared entries from this map (i.e. entries whose value 082 * is a cleared {@link WeakReference}). 083 */ 084 private void clean() { 085 Iterator<Entry<K, WeakReference<V>>> iter = entrySet().iterator(); 086 while (iter.hasNext()) { 087 Entry<K, WeakReference<V>> e = iter.next(); 088 if (e != null && e.getValue() != null 089 && e.getValue().get() == null) { 090 iter.remove(); 091 } 092 } 093 } 094}