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        /**
056         * Returns the proxy class generated by the {@link ProxyClassGenerator} using the specified {@link ClassLoader} and
057         * array of proxy classes.
058         * 
059         * @param classLoader the classloader
060         * @param proxyClasses the proxy classes
061         * @return the proxy class generated by the {@link ProxyClassGenerator} using the specified {@link ClassLoader} and
062         * array of proxy classes
063         */
064        public synchronized Class getProxyClass( ClassLoader classLoader, Class[] proxyClasses )
065        {
066            final Map classCache = getClassCache( classLoader );
067            final String key = toClassCacheKey( proxyClasses );
068            Class proxyClass;
069            WeakReference proxyClassReference = ( WeakReference )classCache.get( key );
070            if( proxyClassReference == null )
071            {
072                proxyClass = proxyClassGenerator.generateProxyClass( classLoader, proxyClasses );
073                classCache.put( key, new WeakReference( proxyClass ) );
074            }
075            else
076            {
077                synchronized( proxyClassReference )
078                {
079                    proxyClass = ( Class )proxyClassReference.get();
080                    if( proxyClass == null )
081                    {
082                        proxyClass = proxyClassGenerator.generateProxyClass( classLoader, proxyClasses );
083                        classCache.put( key, new WeakReference( proxyClass ) );
084                    }
085                }
086            }
087            return proxyClass;
088        }
089    
090        private Map getClassCache( ClassLoader classLoader )
091        {
092            Map cache = ( Map )loaderToClassCache.get( classLoader );
093            if( cache == null )
094            {
095                cache = new HashMap();
096                loaderToClassCache.put( classLoader, cache );
097            }
098            return cache;
099        }
100    
101        private String toClassCacheKey( Class[] proxyClasses )
102        {
103            final StringBuffer sb = new StringBuffer();
104            for( int i = 0; i < proxyClasses.length; i++ )
105            {
106                Class proxyInterface = proxyClasses[i];
107                sb.append( proxyInterface.getName() );
108                if( i != proxyClasses.length - 1 )
109                {
110                    sb.append( "," );
111                }
112            }
113            return sb.toString();
114        }
115    }
116