001: // Copyright 2006, 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:
015: package org.apache.tapestry.ioc.internal.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newMap;
019:
020: import java.util.Set;
021: import java.util.Map;
022:
023: import org.apache.tapestry.ioc.services.ClassFabUtils;
024:
025: import javassist.ClassPath;
026: import javassist.ClassPool;
027: import javassist.CtClass;
028: import javassist.LoaderClassPath;
029: import javassist.NotFoundException;
030:
031: /**
032: * Used to ensure that {@link javassist.ClassPool#appendClassPath(javassist.ClassPath)} is invoked
033: * within a synchronized lock, and also handles tricky class loading issues (caused by the creation
034: * of classes, and class loaders, at runtime).
035: */
036: public class ClassFactoryClassPool extends ClassPool {
037: /**
038: * Used to identify which class loaders have already been integrated into the pool.
039: */
040: private final Set<ClassLoader> _allLoaders = newSet();
041:
042: private final Map<ClassLoader, ClassPath> _leafLoaders = newMap();
043:
044: public ClassFactoryClassPool(ClassLoader contextClassLoader) {
045: super (null);
046:
047: addClassLoaderIfNeeded(contextClassLoader);
048: }
049:
050: /**
051: * Returns the nearest super-class of the provided class that can be converted to a
052: * {@link CtClass}. This is used to filter out Hibernate-style proxies (created as subclasses
053: * of oridnary classes). This will automatically add the class' classLoader to the pool's class
054: * path.
055: *
056: * @param clazz
057: * class to import
058: * @return clazz, or a super-class of clazz
059: */
060: public Class importClass(Class clazz) {
061: addClassLoaderIfNeeded(clazz.getClassLoader());
062:
063: while (true) {
064: try {
065: String name = ClassFabUtils.toJavaClassName(clazz);
066:
067: get(name);
068:
069: break;
070: } catch (NotFoundException ex) {
071: clazz = clazz.getSuperclass();
072: }
073: }
074:
075: return clazz;
076: }
077:
078: /**
079: * Convienience method for adding to the ClassPath for a particular class loader.
080: * <p>
081: *
082: * @param loader
083: * the class loader to add (derived from a loaded class, and may be null for some
084: * system classes)
085: */
086: public synchronized void addClassLoaderIfNeeded(ClassLoader loader) {
087: Set<ClassLoader> leaves = _leafLoaders.keySet();
088: if (loader == null || leaves.contains(loader)
089: || _allLoaders.contains(loader))
090: return;
091:
092: // Work out if this loader is a child of a loader we have already.
093: ClassLoader existingLeaf = loader;
094: while (existingLeaf != null && !leaves.contains(existingLeaf)) {
095: existingLeaf = existingLeaf.getParent();
096: }
097:
098: if (existingLeaf != null) {
099: // The new loader is a child of an existing leaf.
100: // So we remove the old leaf before we add the new loader
101: ClassPath priorPath = _leafLoaders.get(existingLeaf);
102: removeClassPath(priorPath);
103: _leafLoaders.remove(existingLeaf);
104: }
105:
106: ClassPath path = new LoaderClassPath(loader);
107: _leafLoaders.put(loader, path);
108: insertClassPath(path);
109:
110: ClassLoader l = loader;
111: while (l != null) {
112: _allLoaders.add(l);
113: l = l.getParent();
114: }
115: }
116: }
|