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
018 package org.apache.commons.proxy.factory.util;
019
020 import java.lang.ref.WeakReference;
021 import java.util.HashMap;
022 import java.util.Map;
023 import java.util.WeakHashMap;
024
025 /**
026 * A cache for storing implementation classes for proxies based on a specific type of {@link ProxyClassGenerator}. A
027 * proxy class cache ensures that there is only one class for every
028 * {@link ProxyClassGenerator}/{@link ClassLoader}/proxy class array combination.
029 *
030 * @author James Carman
031 * @since 1.0
032 */
033 public class ProxyClassCache
034 {
035 //**********************************************************************************************************************
036 // Fields
037 //**********************************************************************************************************************
038
039 private final Map loaderToClassCache = new WeakHashMap();
040 private final ProxyClassGenerator proxyClassGenerator;
041
042 //**********************************************************************************************************************
043 // Constructors
044 //**********************************************************************************************************************
045
046 public ProxyClassCache( ProxyClassGenerator proxyClassGenerator )
047 {
048 this.proxyClassGenerator = proxyClassGenerator;
049 }
050
051 //**********************************************************************************************************************
052 // Other Methods
053 //**********************************************************************************************************************
054
055 private Map getClassCache( ClassLoader classLoader )
056 {
057 Map cache = ( Map ) loaderToClassCache.get(classLoader);
058 if( cache == null )
059 {
060 cache = new HashMap();
061 loaderToClassCache.put(classLoader, cache);
062 }
063 return cache;
064 }
065
066 private String toClassCacheKey( Class[] proxyClasses )
067 {
068 final StringBuffer sb = new StringBuffer();
069 for( int i = 0; i < proxyClasses.length; i++ )
070 {
071 Class proxyInterface = proxyClasses[i];
072 sb.append(proxyInterface.getName());
073 if( i != proxyClasses.length - 1 )
074 {
075 sb.append(",");
076 }
077 }
078 return sb.toString();
079 }
080
081 /**
082 * Returns the proxy class generated by the {@link ProxyClassGenerator} using the specified {@link ClassLoader} and
083 * array of proxy classes.
084 *
085 * @param classLoader the classloader
086 * @param proxyClasses the proxy classes
087 * @return the proxy class generated by the {@link ProxyClassGenerator} using the specified {@link ClassLoader} and
088 * array of proxy classes
089 */
090 public synchronized Class getProxyClass( ClassLoader classLoader, Class[] proxyClasses )
091 {
092 final Map classCache = getClassCache(classLoader);
093 final String key = toClassCacheKey(proxyClasses);
094 Class proxyClass;
095 WeakReference proxyClassReference = ( WeakReference ) classCache.get(key);
096 if( proxyClassReference == null )
097 {
098 proxyClass = proxyClassGenerator.generateProxyClass(classLoader, proxyClasses);
099 classCache.put(key, new WeakReference(proxyClass));
100 }
101 else
102 {
103 synchronized( proxyClassReference )
104 {
105 proxyClass = ( Class ) proxyClassReference.get();
106 if( proxyClass == null )
107 {
108 proxyClass = proxyClassGenerator.generateProxyClass(classLoader, proxyClasses);
109 classCache.put(key, new WeakReference(proxyClass));
110 }
111 }
112 }
113 return proxyClass;
114 }
115 }
116