001    // Copyright 2007 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    package org.apache.tapestry.enhance;
015    
016    import java.util.HashSet;
017    import java.util.Set;
018    
019    import javassist.CannotCompileException;
020    import javassist.ClassPath;
021    import javassist.ClassPool;
022    import javassist.CtClass;
023    import javassist.LoaderClassPath;
024    
025    /**
026     * Used to ensure that {@link javassist.ClassPool#appendClassPath(javassist.ClassPath)} is invoked
027     * with a synchronized lock. Additionally, wraps around a shared
028     * {@link org.apache.hivemind.service.impl.ClassFactoryClassLoader}.
029     * 
030     * @author Howard Lewis Ship
031     */
032    public class HiveMindClassPool extends ClassPool
033    {
034        private ClassFactoryClassLoader _loader = new ClassFactoryClassLoader();
035        
036        /**
037         * Used to identify which class loaders have already been integrated into the pool.
038         */
039        private Set _loaders = new HashSet();
040    
041        public HiveMindClassPool()
042        {
043            super(null);
044    
045            appendClassLoader(Thread.currentThread().getContextClassLoader());
046        }
047    
048        /**
049         * Convienience method for adding to the ClassPath for a particular class loader.
050         */
051        public synchronized void appendClassLoader(ClassLoader loader)
052        {
053            if (loader == null || loader == _loader || _loaders.contains(loader))
054                return;
055    
056            _loader.addDelegateLoader(loader);
057            
058            ClassPath path = new LoaderClassPath(loader);
059    
060            appendClassPath(path);
061    
062            _loaders.add(loader);
063        }
064    
065        /**
066         * Invoked to convert an fabricated class into a real class. The new classes' class loader will
067         * be the delegating ClassFactoryClassLoader, which has visibility to all class loaders for all
068         * modules.
069         * 
070         * @since 1.1
071         */
072        public Class toClass(CtClass ctClass) throws CannotCompileException
073        {
074            return toClass(ctClass, false);
075        }
076        
077        public Class toClass(CtClass ctClass, boolean detach) throws CannotCompileException
078        {
079            Class clazz = ctClass.toClass(_loader, getClass().getProtectionDomain());
080            
081            if (detach)
082                ctClass.detach();
083            
084            return clazz;
085        }
086        
087        public Set getLoaders()
088        {
089            return _loaders;
090        }
091    }