1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.scopedpool;
17
18import java.util.ArrayList;
19import java.util.Collections;
20import java.util.Iterator;
21import java.util.Map;
22import java.util.WeakHashMap;
23
24import javassist.ClassPool;
25import javassist.LoaderClassPath;
26
27/**
28 * An implementation of <code>ScopedClassPoolRepository</code>.
29 * It is an singleton.
30 *
31 * @author <a href="kabir.khan@jboss.com">Kabir Khan</a>
32 * @version $Revision: 1.4 $
33 */
34public class ScopedClassPoolRepositoryImpl implements ScopedClassPoolRepository {
35    /** The instance */
36    private static final ScopedClassPoolRepositoryImpl instance = new ScopedClassPoolRepositoryImpl();
37
38    /** Whether to prune */
39    private boolean prune = true;
40
41    /** Whether to prune when added to the classpool's cache */
42    boolean pruneWhenCached;
43
44    /** The registered classloaders */
45    protected Map registeredCLs = Collections
46            .synchronizedMap(new WeakHashMap());
47
48    /** The default class pool */
49    protected ClassPool classpool;
50
51    /** The factory for creating class pools */
52    protected ScopedClassPoolFactory factory = new ScopedClassPoolFactoryImpl();
53
54    /**
55     * Get the instance.
56     *
57     * @return the instance.
58     */
59    public static ScopedClassPoolRepository getInstance() {
60        return instance;
61    }
62
63    /**
64     * Singleton.
65     */
66    private ScopedClassPoolRepositoryImpl() {
67        classpool = ClassPool.getDefault();
68        // FIXME This doesn't look correct
69        ClassLoader cl = Thread.currentThread().getContextClassLoader();
70        classpool.insertClassPath(new LoaderClassPath(cl));
71    }
72
73    /**
74     * Returns the value of the prune attribute.
75     *
76     * @return the prune.
77     */
78    public boolean isPrune() {
79        return prune;
80    }
81
82    /**
83     * Set the prune attribute.
84     *
85     * @param prune     a new value.
86     */
87    public void setPrune(boolean prune) {
88        this.prune = prune;
89    }
90
91    /**
92     * Create a scoped classpool.
93     *
94     * @param cl    the classloader.
95     * @param src   the original classpool.
96     * @return the classpool
97     */
98    public ScopedClassPool createScopedClassPool(ClassLoader cl, ClassPool src) {
99        return factory.create(cl, src, this);
100    }
101
102    public ClassPool findClassPool(ClassLoader cl) {
103        if (cl == null)
104            return registerClassLoader(ClassLoader.getSystemClassLoader());
105
106        return registerClassLoader(cl);
107    }
108
109    /**
110     * Register a classloader.
111     *
112     * @param ucl       the classloader.
113     * @return the classpool
114     */
115    public ClassPool registerClassLoader(ClassLoader ucl) {
116        synchronized (registeredCLs) {
117            // FIXME: Probably want to take this method out later
118            // so that AOP framework can be independent of JMX
119            // This is in here so that we can remove a UCL from the ClassPool as
120            // a
121            // ClassPool.classpath
122            if (registeredCLs.containsKey(ucl)) {
123                return (ClassPool)registeredCLs.get(ucl);
124            }
125            ScopedClassPool pool = createScopedClassPool(ucl, classpool);
126            registeredCLs.put(ucl, pool);
127            return pool;
128        }
129    }
130
131    /**
132     * Get the registered classloaders.
133     */
134    public Map getRegisteredCLs() {
135        clearUnregisteredClassLoaders();
136        return registeredCLs;
137    }
138
139    /**
140     * This method will check to see if a register classloader has been
141     * undeployed (as in JBoss)
142     */
143    public void clearUnregisteredClassLoaders() {
144        ArrayList toUnregister = null;
145        synchronized (registeredCLs) {
146            Iterator it = registeredCLs.values().iterator();
147            while (it.hasNext()) {
148                ScopedClassPool pool = (ScopedClassPool)it.next();
149                if (pool.isUnloadedClassLoader()) {
150                    it.remove();
151                    ClassLoader cl = pool.getClassLoader();
152                    if (cl != null) {
153                        if (toUnregister == null) {
154                            toUnregister = new ArrayList();
155                        }
156                        toUnregister.add(cl);
157                    }
158                }
159            }
160            if (toUnregister != null) {
161                for (int i = 0; i < toUnregister.size(); i++) {
162                    unregisterClassLoader((ClassLoader)toUnregister.get(i));
163                }
164            }
165        }
166    }
167
168    public void unregisterClassLoader(ClassLoader cl) {
169        synchronized (registeredCLs) {
170            ScopedClassPool pool = (ScopedClassPool)registeredCLs.remove(cl);
171            if (pool != null)
172                pool.close();
173        }
174    }
175
176    public void insertDelegate(ScopedClassPoolRepository delegate) {
177        // Noop - this is the end
178    }
179
180    public void setClassPoolFactory(ScopedClassPoolFactory factory) {
181        this.factory = factory;
182    }
183
184    public ScopedClassPoolFactory getClassPoolFactory() {
185        return factory;
186    }
187}
188