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