169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/*
269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit.
369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version
669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with
769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License.  Alternatively, the contents of this file may be used under
869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later.
969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis,
1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the
1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License.
1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist.scopedpool;
1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.ArrayList;
1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Collections;
2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Iterator;
2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.Map;
2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.util.WeakHashMap;
2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.ClassPool;
2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport javassist.LoaderClassPath;
2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/**
2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * An implementation of <code>ScopedClassPoolRepository</code>.
2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It is an singleton.
3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal *
3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @version $Revision: 1.4 $
3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */
3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository {
3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** The instance */
3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private static final ScopedClassPoolRepositoryImpl instance = new ScopedClassPoolRepositoryImpl();
3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** Whether to prune */
3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private boolean prune = true;
4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** Whether to prune when added to the classpool's cache */
4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    boolean pruneWhenCached;
4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** The registered classloaders */
4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected Map registeredCLs = Collections
4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            .synchronizedMap(new WeakHashMap());
4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** The default class pool */
4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ClassPool classpool;
5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /** The factory for creating class pools */
5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    protected ScopedClassPoolFactory factory = new ScopedClassPoolFactoryImpl();
5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Get the instance.
5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the instance.
5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public static ScopedClassPoolRepository getInstance() {
6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return instance;
6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Singleton.
6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    private ScopedClassPoolRepositoryImpl() {
6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classpool = ClassPool.getDefault();
6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // FIXME This doesn't look correct
6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ClassLoader cl = Thread.currentThread().getContextClassLoader();
7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        classpool.insertClassPath(new LoaderClassPath(cl));
7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Returns the value of the prune attribute.
7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the prune.
7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public boolean isPrune() {
7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return prune;
8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Set the prune attribute.
8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param prune     a new value.
8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setPrune(boolean prune) {
8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.prune = prune;
8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Create a scoped classpool.
9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param cl    the classloader.
9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param src   the original classpool.
9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the classpool
9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) {
9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return factory.create(cl, src, this);
10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ClassPool findClassPool(ClassLoader cl) {
10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        if (cl == null)
10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return registerClassLoader(ClassLoader.getSystemClassLoader());
10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return registerClassLoader(cl);
10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Register a classloader.
11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     *
11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @param ucl       the classloader.
11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * @return the classpool
11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ClassPool registerClassLoader(ClassLoader ucl) {
11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        synchronized (registeredCLs) {
11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // FIXME: Probably want to take this method out later
11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // so that AOP framework can be independent of JMX
11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // This is in here so that we can remove a UCL from the ClassPool as
12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // a
12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            // ClassPool.classpath
12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (registeredCLs.containsKey(ucl)) {
12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                return (ClassPool)registeredCLs.get(ucl);
12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ScopedClassPool pool = createScopedClassPool(ucl, classpool);
12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            registeredCLs.put(ucl, pool);
12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            return pool;
12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * Get the registered classloaders.
13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public Map getRegisteredCLs() {
13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        clearUnregisteredClassLoaders();
13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return registeredCLs;
13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    /**
14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * This method will check to see if a register classloader has been
14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     * undeployed (as in JBoss)
14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal     */
14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void clearUnregisteredClassLoaders() {
14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        ArrayList toUnregister = null;
14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        synchronized (registeredCLs) {
14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            Iterator it = registeredCLs.values().iterator();
14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            while (it.hasNext()) {
14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                ScopedClassPool pool = (ScopedClassPool)it.next();
14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                if (pool.isUnloadedClassLoader()) {
15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    it.remove();
15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    ClassLoader cl = pool.getClassLoader();
15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    if (cl != null) {
15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        if (toUnregister == null) {
15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                            toUnregister = new ArrayList();
15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        }
15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                        toUnregister.add(cl);
15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    }
15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (toUnregister != null) {
16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                for (int i = 0; i < toUnregister.size(); i++) {
16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                    unregisterClassLoader((ClassLoader)toUnregister.get(i));
16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                }
16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            }
16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void unregisterClassLoader(ClassLoader cl) {
16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        synchronized (registeredCLs) {
17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            ScopedClassPool pool = (ScopedClassPool)registeredCLs.remove(cl);
17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal            if (pool != null)
17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal                pool.close();
17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        }
17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void insertDelegate(ScopedClassPoolRepository delegate) {
17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        // Noop - this is the end
17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
17969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public void setClassPoolFactory(ScopedClassPoolFactory factory) {
18169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        this.factory = factory;
18269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal
18469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    public ScopedClassPoolFactory getClassPoolFactory() {
18569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal        return factory;
18669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal    }
18769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal}
188