001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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 * 017 */ 018package org.apache.bcel.util; 019 020import java.util.LinkedHashMap; 021import java.util.Map; 022 023import org.apache.bcel.classfile.JavaClass; 024 025/** 026 * Maintains a least-recently-used (LRU) cache of {@link JavaClass} with maximum size {@code cacheSize}. 027 * 028 * <p> 029 * This repository supports a class path consisting of too many JAR files to handle in {@link ClassPathRepository} or 030 * {@link MemorySensitiveClassPathRepository} without causing {@code OutOfMemoryError}. 031 * </p> 032 * 033 * @since 6.4.0 034 */ 035public class LruCacheClassPathRepository extends AbstractClassPathRepository { 036 037 private final LinkedHashMap<String, JavaClass> loadedClasses; 038 039 public LruCacheClassPathRepository(final ClassPath path, final int cacheSize) { 040 super(path); 041 042 if (cacheSize < 1) { 043 throw new IllegalArgumentException("cacheSize must be a positive number."); 044 } 045 final int initialCapacity = (int) (0.75 * cacheSize); 046 final boolean accessOrder = true; // Evicts least-recently-accessed 047 loadedClasses = new LinkedHashMap<String, JavaClass>(initialCapacity, cacheSize, accessOrder) { 048 049 private static final long serialVersionUID = 1L; 050 051 @Override 052 protected boolean removeEldestEntry(final Map.Entry<String, JavaClass> eldest) { 053 return size() > cacheSize; 054 } 055 }; 056 } 057 058 @Override 059 public JavaClass findClass(final String className) { 060 return loadedClasses.get(className); 061 } 062 063 @Override 064 public void storeClass(final JavaClass javaClass) { 065 // Not storing parent's _loadedClass 066 loadedClasses.put(javaClass.getClassName(), javaClass); 067 javaClass.setRepository(this); 068 } 069 070 @Override 071 public void removeClass(final JavaClass javaClass) { 072 loadedClasses.remove(javaClass.getClassName()); 073 } 074 075 @Override 076 public void clear() { 077 loadedClasses.clear(); 078 } 079}