001// Copyright 2006, 2007, 2008 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
015package org.apache.tapestry5.ioc.internal.services;
016
017import javassist.CtClass;
018import javassist.NotFoundException;
019import org.apache.tapestry5.ioc.services.ClassFabUtils;
020
021import java.security.ProtectionDomain;
022
023/**
024 * Wrapper around Javassist's {@link javassist.ClassPool} that manages the creation of new instances of {@link
025 * javassist.CtClass} and converts finished CtClass's into instantiable Classes.
026 */
027public class CtClassSourceImpl implements CtClassSource
028{
029    private static final String WRITE_DIR = System.getProperty("javassist-write-dir");
030
031    private final ClassFactoryClassPool pool;
032
033    private final ClassLoader loader;
034
035    private final ProtectionDomain domain = getClass().getProtectionDomain();
036
037    private int createdClassCount = 0;
038
039    /**
040     * Returns the number of classes (and interfaces) created by this source.
041     */
042    public synchronized int getCreatedClassCount()
043    {
044        return createdClassCount;
045    }
046
047    public CtClassSourceImpl(ClassFactoryClassPool pool, ClassLoader loader)
048    {
049        this.pool = pool;
050        this.loader = loader;
051    }
052
053    public synchronized CtClass toCtClass(Class searchClass)
054    {
055        ClassLoader loader = searchClass.getClassLoader();
056
057        // Add the class loader for the searchClass to the class pool and
058        // delegating class loader if needed.
059
060        pool.addClassLoaderIfNeeded(loader);
061
062        String name = ClassFabUtils.toJavaClassName(searchClass);
063
064        return toCtClass(name);
065    }
066
067    public CtClass toCtClass(String name)
068    {
069        try
070        {
071            return pool.get(name);
072        }
073        catch (NotFoundException ex)
074        {
075            throw new RuntimeException(ServiceMessages.unableToLookupClass(name, ex), ex);
076        }
077    }
078
079    public CtClass newClass(String name, Class superClass)
080    {
081        CtClass ctSuperClass = toCtClass(superClass);
082
083        return pool.makeClass(name, ctSuperClass);
084    }
085
086
087    public Class createClass(CtClass ctClass)
088    {
089        if (WRITE_DIR != null) writeClass(ctClass);
090
091        try
092        {
093            Class result = pool.toClass(ctClass, loader, domain);
094
095            synchronized (this)
096            {
097                createdClassCount++;
098            }
099
100            return result;
101        }
102        catch (Throwable ex)
103        {
104            throw new RuntimeException(ServiceMessages.unableToWriteClass(ctClass, ex), ex);
105        }
106    }
107
108    private void writeClass(CtClass ctClass)
109    {
110        try
111        {
112            ctClass.debugWriteFile(WRITE_DIR);
113        }
114        catch (Exception ex)
115        {
116            ex.printStackTrace(System.err);
117        }
118    }
119}