/*******************************************************************************
* Copyright (c) 2010 Freescale Semiconductor.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Serge Beauchamp (Freescale Semiconductor) - initial API and implementation
*******************************************************************************/
package com.freescale.deadlockpreventer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ListIterator;
// We use a custom object cache because we can't use a simple HashMap<Object>, since the object.hashCode()
// can be overridden by clients and cause deadlocks.
public class ObjectCache<T> {
HashMap<Integer, ArrayList<ObjectCache.Entry<T>>> cache = new HashMap<Integer, ArrayList<ObjectCache.Entry<T>>>();
public T get(Object obj) {
return getFromKey(getKey(obj), obj);
}
public T getFromKey(Object key, Object obj) {
ArrayList<ObjectCache.Entry<T>> cacheLine = cache.get(key);
if (cacheLine != null) {
ListIterator<ObjectCache.Entry<T>> iterator = cacheLine.listIterator(cacheLine.size());
while (iterator.hasPrevious()) {
ObjectCache.Entry<T> entry = iterator.previous();
if (entry.object == obj)
return entry.value;
}
}
return null;
}
public T getOrCreate(Object obj, Class<T> cls) {
Integer key = getKey(obj);
ArrayList<ObjectCache.Entry<T>> cacheLine = cache.get(key);
if (cacheLine != null) {
ListIterator<ObjectCache.Entry<T>> iterator = cacheLine.listIterator(cacheLine.size());
while (iterator.hasPrevious()) {
ObjectCache.Entry<T> entry = iterator.previous();
if (entry.object == obj)
return entry.value;
}
} else {
cacheLine = new ArrayList<ObjectCache.Entry<T>>();
cache.put(key, cacheLine);
}
T value;
try {
value = cls.newInstance();
} catch (Throwable e) {
e.printStackTrace();
return null;
}
cacheLine.add(new ObjectCache.Entry<T>(obj, value));
return value;
}
public static Integer getKey(Object obj) {
Class<?> cls = obj.getClass();
if (cls.equals(CustomLock.class))
cls = ((CustomLock) obj).lock.getClass();
return System.identityHashCode(obj);
}
public void put(Object obj, T value) {
Integer key = getKey(obj);
ArrayList<ObjectCache.Entry<T>> cacheLine = cache.get(key);
if (cacheLine == null) {
cacheLine = new ArrayList<ObjectCache.Entry<T>>();
cache.put(key, cacheLine);
}
cacheLine.add(new ObjectCache.Entry<T>(obj, value));
}
interface IVisitor<T> {
boolean visit(ObjectCache.Entry<T> obj);
}
static class Entry<E> {
public Entry(Object obj, E value2) {
object = obj;
value = value2;
}
Object object;
E value;
}
public void visitKeyEntries(String key, IVisitor visitor) {
ArrayList<ObjectCache.Entry<T>> cacheLine = cache.get(key);
if (cacheLine != null) {
ListIterator<ObjectCache.Entry<T>> iterator = cacheLine.listIterator();
while (iterator.hasNext()) {
ObjectCache.Entry<T> entry = iterator.next();
if (!visitor.visit(entry))
break;
}
}
}
}