/*******************************************************************************
* Copyright (c) 2012 Google, Inc.
* 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:
* Google, Inc. - initial API and implementation
*******************************************************************************/
package com.windowtester.eclipse.ui.jdt.analysis.util;
import java.util.ArrayList;
import java.util.HashMap;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeHierarchy;
import org.eclipse.jdt.core.JavaModelException;
import com.windowtester.ui.util.Logger;
/**
* Instances of the class <code>TypeHierarchyCache</code> cache one or more
* type hierarchies associated with either types or projects.
*/
public class TypeHierarchyCache
{
/**
* The maximum number of type hierarchies that should be kept in the cache.
*/
private int maxCacheSize;
/**
* A table mapping types and projects to the type hierarchy associated with
* them.
*
* @type HashMap<IJavaElement, ITypeHierarchy>
*/
private HashMap cache;
/**
* A list of the keys in the cache ordered by the time at which they were
* last accessed. The most recently accessed are at the beginning of the
* list.
*
* @type ArrayList<IJavaElement>
*/
private ArrayList mruList;
////////////////////////////////////////////////////////////////////////////
//
// Constructors
//
////////////////////////////////////////////////////////////////////////////
/**
* Initialize a newly created type hierarchy cache to be empty and to have
* the default maximum size.
*/
public TypeHierarchyCache()
{
this(100);
}
/**
* Initialize a newly created type hierarchy cache to be empty.
*
* @param maxCacheSize the maximum number of type hierarchies that should
* be kept in the cache
*/
public TypeHierarchyCache(int maxCacheSize)
{
this.maxCacheSize = maxCacheSize;
cache = new HashMap(maxCacheSize);
mruList = new ArrayList(maxCacheSize);
}
////////////////////////////////////////////////////////////////////////////
//
// Accessing
//
////////////////////////////////////////////////////////////////////////////
/**
* Return a type hierarchy for the class <code>java.lang.Object</code> from
* the given project.
*
* @param project the project used to find the class <code>Object</code>
*
* @return a type hierarchy for the given project
*/
public ITypeHierarchy getTypeHierarchy(IJavaProject project)
{
ITypeHierarchy typeHierarchy;
IType objectType;
typeHierarchy = getHierarchy(project);
if (typeHierarchy == null) {
try {
objectType = project.findType("java.lang.Object");
typeHierarchy = getTypeHierarchy(objectType, project);
if (typeHierarchy != null) {
addHierarchy(project, typeHierarchy);
}
} catch (JavaModelException exception) {
Logger.log("Could not create type hierarchy for project " + project.getElementName(), exception);
}
}
return typeHierarchy;
}
/**
* Return a type hierarchy containing the given type, all supertypes, and
* all subtypes of the given type.
*
* @param type the type around which the type hierarchy is centered
* @param project the project used to identify which classes should be
* included in the hierarchy
*
* @return a type hierarchy for the given type
*/
public ITypeHierarchy getTypeHierarchy(IType type, IJavaProject project)
{
ITypeHierarchy typeHierarchy;
IType[] subtypes;
typeHierarchy = getHierarchy(type);
if (typeHierarchy == null) {
try {
//long startTime = System.currentTimeMillis();
//System.out.println(" " + startTime + " start creating type hierarchy for " + type.getElementName());
typeHierarchy = type.newTypeHierarchy(project, null);
//long endTime = System.currentTimeMillis();
//System.out.println(" " + endTime + " finished (" + (endTime - startTime) + "ms)");
addHierarchy(type, typeHierarchy);
subtypes = typeHierarchy.getAllSubtypes(type);
for (int i = 0; i < subtypes.length; i++) {
cache.put(subtypes[i], typeHierarchy);
}
} catch (JavaModelException exception) {
Logger.log("Could not create type hierarchy for the type " + type.getElementName(), exception);
}
}
return typeHierarchy;
}
////////////////////////////////////////////////////////////////////////////
//
// Accessing
//
////////////////////////////////////////////////////////////////////////////
private ITypeHierarchy getHierarchy(IJavaElement key)
{
ITypeHierarchy typeHierarchy;
typeHierarchy = (ITypeHierarchy) cache.get(key);
if (typeHierarchy != null) {
mruList.remove(key);
mruList.add(0, key);
}
return typeHierarchy;
}
private void addHierarchy(IJavaElement key, ITypeHierarchy typeHierarchy)
{
int cacheSize;
Object removedKey;
cacheSize = mruList.size();
if (cacheSize >= maxCacheSize) {
removedKey = mruList.remove(cacheSize - 1);
cache.remove(removedKey);
}
mruList.add(0, key);
cache.put(key, typeHierarchy);
}
}