Skip to content
Snippets Groups Projects
Commit 07151405 authored by Nils Christian Ehmke's avatar Nils Christian Ehmke
Browse files

Added the LRUCache and replaced the deprecated (and forbidden) use of sun.misc.Cache with it.

parent 25608d12
Branches
Tags
No related merge requests found
...@@ -83,7 +83,6 @@ public class DependenciesBean { ...@@ -83,7 +83,6 @@ public class DependenciesBean {
final MIDependency dependency = FileManager.getInstance().uploadDependency(file); final MIDependency dependency = FileManager.getInstance().uploadDependency(file);
if (dependency != null) { if (dependency != null) {
// Is is possible that we already have a dependency with the same name and have to remove it first. // Is is possible that we already have a dependency with the same name and have to remove it first.
for (final MIDependency dep : this.dependencies) { for (final MIDependency dep : this.dependencies) {
if (dep.getFilePath().equals(dependency.getFilePath())) { if (dep.getFilePath().equals(dependency.getFilePath())) {
this.dependencies.remove(dep); this.dependencies.remove(dep);
......
/***************************************************************************
* Copyright 2012 by
* + Christian-Albrechts-University of Kiel
* + Department of Computer Science
* + Software Engineering Group
* and others.
*
* Licensed 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.
***************************************************************************/
package kieker.webgui.common;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
/**
* This is a thread-safe cache, which can be used to cache objects under a specific key. This class is a LRU cache.
*
* @author Nils Christian Ehmke
*
* @param <Key>
* The type for the keys.
* @param <Value>
* The type for the values.
*/
public class LRUCache<Key, Value> {
/**
* This is the map which is used to store the entries.
*/
private final HashMap<Key, Value> hashMap;
private final int maxSize;
/**
* Creates a new instance of this class using the given size as maximal cache size.
*
* @param size
* The maximal cache size.
*/
public LRUCache(final int size) {
this.maxSize = size;
this.hashMap = new FixedLinkedHashMap();
}
/**
* This method adds a given value within the cache, using the given key. If a value with the same key does already exist, it will be replaced. If the entry would
* excess the maximal cache size, the oldest entry will be removed.
*
* @param key
* The key used to store the value.
* @param value
* The value to be stored.
*/
public void add(final Key key, final Value value) {
synchronized (this.hashMap) {
this.hashMap.put(key, value);
}
}
/**
* This method delivers the value to the key or null, if the value doesn't exist.
*
* @param key
* The key to the value.
* @return The corresponding value.
*/
public Value get(final Key key) {
synchronized (this.hashMap) {
return this.hashMap.get(key);
}
}
/**
* A modified version of {@link LinkedHashMap} which has a fixed size. Each time the {@code put} or {@code putAll} method exceeds the size of the
* {@link LRUCache}, the oldest entry is being removed.
*
* @author Nils Christian Ehmke
*/
private class FixedLinkedHashMap extends LinkedHashMap<Key, Value> {
/**
* The serial version uid.
*/
private static final long serialVersionUID = 1L;
/**
* Creates a new instance of this class, using the LRUCache's maximal size as the size of the map.
*/
public FixedLinkedHashMap() {
super(LRUCache.this.maxSize);
}
@Override
protected boolean removeEldestEntry(final Entry<Key, Value> eldest) {
return this.size() > LRUCache.this.maxSize;
}
}
}
...@@ -31,7 +31,6 @@ import java.util.jar.JarFile; ...@@ -31,7 +31,6 @@ import java.util.jar.JarFile;
import kieker.analysis.plugin.AbstractPlugin; import kieker.analysis.plugin.AbstractPlugin;
import kieker.analysis.plugin.annotation.Plugin; import kieker.analysis.plugin.annotation.Plugin;
import kieker.analysis.repository.AbstractRepository; import kieker.analysis.repository.AbstractRepository;
import sun.misc.Cache;
/** /**
* This tool class can be used to find all plugins and repositories within a given jar file - assuming that the <code>PluginClassLoader</code> knows these jars. * This tool class can be used to find all plugins and repositories within a given jar file - assuming that the <code>PluginClassLoader</code> knows these jars.
...@@ -42,19 +41,19 @@ import sun.misc.Cache; ...@@ -42,19 +41,19 @@ import sun.misc.Cache;
*/ */
public final class PluginFinder { public final class PluginFinder {
private static final Cache PLUGIN_CACHE; private static final LRUCache<URL, List<Class<AbstractPlugin>>> PLUGIN_CACHE;
private static final Cache REPOSITORY_CACHE; private static final LRUCache<URL, List<Class<AbstractRepository>>> REPOSITORY_CACHE;
static { static {
PLUGIN_CACHE = new Cache(15); PLUGIN_CACHE = new LRUCache<URL, List<Class<AbstractPlugin>>>(15);
REPOSITORY_CACHE = new Cache(15); REPOSITORY_CACHE = new LRUCache<URL, List<Class<AbstractRepository>>>(15);
} }
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
*/ */
private PluginFinder() { private PluginFinder() {
/* No code necessary. */ // No code necessary.
} }
/** /**
...@@ -66,7 +65,7 @@ public final class PluginFinder { ...@@ -66,7 +65,7 @@ public final class PluginFinder {
*/ */
public static List<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url) { public static List<Class<AbstractRepository>> getAllRepositoriesWithinJar(final URL url) {
// TODO: Merge this with the other method // TODO: Merge this with the other method
final List<Class<AbstractRepository>> repositoryClasses = (List<Class<AbstractRepository>>) PluginFinder.REPOSITORY_CACHE.get(url); final List<Class<AbstractRepository>> repositoryClasses = PluginFinder.REPOSITORY_CACHE.get(url);
if (repositoryClasses != null) { if (repositoryClasses != null) {
return repositoryClasses; return repositoryClasses;
} }
...@@ -92,7 +91,7 @@ public final class PluginFinder { ...@@ -92,7 +91,7 @@ public final class PluginFinder {
} }
} }
jarFile.close(); jarFile.close();
PluginFinder.REPOSITORY_CACHE.put(url, result); PluginFinder.REPOSITORY_CACHE.add(url, result);
return result; return result;
} catch (final IOException ex) { } catch (final IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
...@@ -109,7 +108,7 @@ public final class PluginFinder { ...@@ -109,7 +108,7 @@ public final class PluginFinder {
* @return A list containing all available plugin-classes or null, if an exception occurred. * @return A list containing all available plugin-classes or null, if an exception occurred.
*/ */
public static List<Class<AbstractPlugin>> getAllPluginsWithinJar(final URL url) { public static List<Class<AbstractPlugin>> getAllPluginsWithinJar(final URL url) {
final List<Class<AbstractPlugin>> pluginClasses = (List<Class<AbstractPlugin>>) PluginFinder.PLUGIN_CACHE.get(url); final List<Class<AbstractPlugin>> pluginClasses = PluginFinder.PLUGIN_CACHE.get(url);
if (pluginClasses != null) { if (pluginClasses != null) {
return pluginClasses; return pluginClasses;
} }
...@@ -135,7 +134,7 @@ public final class PluginFinder { ...@@ -135,7 +134,7 @@ public final class PluginFinder {
} }
} }
jarFile.close(); jarFile.close();
PluginFinder.PLUGIN_CACHE.put(url, result); PluginFinder.PLUGIN_CACHE.add(url, result);
return result; return result;
} catch (final IOException ex) { } catch (final IOException ex) {
ex.printStackTrace(); ex.printStackTrace();
......
...@@ -21,8 +21,6 @@ package kieker.webgui.converter; ...@@ -21,8 +21,6 @@ package kieker.webgui.converter;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import javax.faces.component.UIComponent; import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext; import javax.faces.context.FacesContext;
...@@ -31,6 +29,7 @@ import javax.faces.convert.FacesConverter; ...@@ -31,6 +29,7 @@ import javax.faces.convert.FacesConverter;
import kieker.analysis.model.analysisMetaModel.MIDependency; import kieker.analysis.model.analysisMetaModel.MIDependency;
import kieker.webgui.common.FileManager; import kieker.webgui.common.FileManager;
import kieker.webgui.common.LRUCache;
import kieker.webgui.common.PluginFinder; import kieker.webgui.common.PluginFinder;
/** /**
...@@ -57,13 +56,13 @@ public class MIDependencyToCountPluginsConverter implements Converter { ...@@ -57,13 +56,13 @@ public class MIDependencyToCountPluginsConverter implements Converter {
* This map is the cache and contains the number of plugins within the * This map is the cache and contains the number of plugins within the
* dependencies. * dependencies.
*/ */
private final Map<MIDependency, String> cache; private final LRUCache<MIDependency, String> cache;
/** /**
* Creates a new instance of this class. * Creates a new instance of this class.
*/ */
public MIDependencyToCountPluginsConverter() { public MIDependencyToCountPluginsConverter() {
this.cache = new HashMap<MIDependency, String>(); this.cache = new LRUCache<MIDependency, String>(MIDependencyToCountPluginsConverter.MAX_CACHE_SIZE);
} }
/** /**
...@@ -102,24 +101,21 @@ public class MIDependencyToCountPluginsConverter implements Converter { ...@@ -102,24 +101,21 @@ public class MIDependencyToCountPluginsConverter implements Converter {
if (!(o instanceof MIDependency)) { if (!(o instanceof MIDependency)) {
return ""; return "";
} else { } else {
// Try to find the library within the cache. final MIDependency dependency = (MIDependency) o;
if (this.cache.containsKey(o)) { // Try to find the string within the cache.
return this.cache.get(o); String result = this.cache.get(dependency);
} if (result == null) {
// If the cache is too big, remove one of the objects. // We have to create the string first
if (this.cache.size() > MIDependencyToCountPluginsConverter.MAX_CACHE_SIZE) {
this.cache.remove(this.cache.keySet().iterator().next());
}
String result;
try { try {
result = Integer.toString(PluginFinder.getAllPluginsWithinJar(new URL("file", "localhost", FileManager.getInstance().getFullPath((MIDependency) o))) result = Integer.toString(PluginFinder.getAllPluginsWithinJar(new URL("file", "localhost", FileManager.getInstance().getFullPath(dependency)))
.size()); .size());
} catch (final MalformedURLException ex) { // Remember it for the next time
result = ""; this.cache.add(dependency, result);
} catch (final NullPointerException ex) { } catch (final MalformedURLException e) {
result = ""; result = "";
} }
this.cache.put((MIDependency) o, result); }
return result; return result;
} }
} }
......
package kieker.webgui.common;
import junit.framework.Assert;
import junit.framework.TestCase;
import org.junit.Test;
/**
* TestCase for {@link LRUCache}.
*
* @author Nils Christian Ehmke
* @version 1.0
*/
public class LRUCacheTest extends TestCase {
/**
* Creates a new instance of this class.
*/
public LRUCacheTest() {}
@Test
public void testEntryStorage() {
final int n = 5;
final LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>(n);
// Make sure that there is nothing stored under the given values yet.
for (int i = 0; i < n; i++) {
Assert.assertNull(cache.get(i));
}
// Store everything
for (int i = 0; i < n; i++) {
cache.add(i, n - i);
}
// Make sure that the values are still available
for (int i = 0; i < n; i++) {
Assert.assertEquals((Integer) (n - i), cache.get(i));
}
// Overwrite an entry
cache.add(0, 0);
// Make sure that it worked
Assert.assertEquals((Integer) 0, cache.get(0));
}
@Test
public void testMaximalStorage() {
final int n = 5;
final LRUCache<Integer, Integer> cache = new LRUCache<Integer, Integer>(n);
// Make sure that there is nothing stored under the given values yet.
for (int i = 0; i < n; i++) {
Assert.assertNull(cache.get(i));
}
// Store everything and exceed the size
for (int i = 0; i < n + 1; i++) {
cache.add(i, n - i);
}
// Make sure that the values are still available
for (int i = 1; i < n + 1; i++) {
Assert.assertEquals((Integer) (n - i), cache.get(i));
}
// Make sure that the oldest entry isn't available
Assert.assertNull(cache.get(0));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment