KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mx > loading > UnifiedClassLoader


1 /*
2   * JBoss, Home of Professional Open Source
3   * Copyright 2005, JBoss Inc., and individual contributors as indicated
4   * by the @authors tag. See the copyright.txt in the distribution for a
5   * full listing of individual contributors.
6   *
7   * This is free software; you can redistribute it and/or modify it
8   * under the terms of the GNU Lesser General Public License as
9   * published by the Free Software Foundation; either version 2.1 of
10   * the License, or (at your option) any later version.
11   *
12   * This software is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   * Lesser General Public License for more details.
16   *
17   * You should have received a copy of the GNU Lesser General Public
18   * License along with this software; if not, write to the Free
19   * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20   * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21   */

22 package org.jboss.mx.loading;
23
24 import java.net.URL JavaDoc;
25 import java.security.CodeSource JavaDoc;
26 import java.security.Permission JavaDoc;
27 import java.security.PermissionCollection JavaDoc;
28 import java.security.Policy JavaDoc;
29 import java.security.ProtectionDomain JavaDoc;
30 import java.util.Enumeration JavaDoc;
31
32 import javax.management.MBeanServer JavaDoc;
33 import javax.management.MalformedObjectNameException JavaDoc;
34 import javax.management.ObjectName JavaDoc;
35
36 import org.jboss.logging.Logger;
37 import org.jboss.util.loading.Translatable;
38
39 /**
40 * A ClassLoader which loads classes from a single URL in conjunction with
41 * the {@link LoaderRepository}. Notice that this classloader does
42 * not work independently of the repository. A repository reference
43 * must be provided via the constructor or the classloader must be explicitly
44 * registered to the repository before any attempt to load a class.
45 *
46 * At this point this is little more than an abstract class maintained as the
47 * interface for class loaders as the algorithm of the UnifiedLoaderRepository
48 * fails with deadlocks, and several other class loading exceptions in multi-
49 * threaded environments.
50 *
51 * @author <a HREF="marc.fleury@jboss.org">Marc Fleury</a>
52 * @author <a HREF="christoph.jung@jboss.org">Christoph G. Jung</a>
53 * @author <a HREF="scott.stark@jboss.org">Scott Stark</a>
54 * @author <a HREF="juha@jboss.org">Juha Lindfors</a>
55 * @author <a HREF="bill@jboss.org">Bill Burke</a>
56 * @version <tt>$Revision: 44243 $</tt>
57 */

58 public class UnifiedClassLoader extends RepositoryClassLoader
59    implements UnifiedClassLoaderMBean, Translatable
60 {
61    // Static --------------------------------------------------------
62

63    private static final Logger log = Logger.getLogger(UnifiedClassLoader.class);
64
65    // Attributes ----------------------------------------------------
66

67    /** One URL per ClassLoader in our case */
68    protected URL JavaDoc url = null;
69    /** An optional URL from which url may have been copied. It is used to
70     allow the security permissions to be based on a static url namespace. */

71    protected URL JavaDoc origURL = null;
72
73    // Constructors --------------------------------------------------
74
/**
75     * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
76     * classloader repository.
77     *
78     * @param url the single URL to load classes from.
79     */

80    public UnifiedClassLoader(URL JavaDoc url)
81    {
82       this(url, (URL JavaDoc) null);
83    }
84    /**
85     * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
86     * classloader repository.
87     *
88     * @param url the single URL to load classes from.
89     * @param origURL the possibly null original URL from which url may
90     * be a local copy or nested jar.
91     */

92    public UnifiedClassLoader(URL JavaDoc url, URL JavaDoc origURL)
93    {
94       this(url, origURL, UnifiedClassLoader.class.getClassLoader());
95    }
96
97    /** Construct a UnifiedClassLoader without registering with the
98     * classloader repository.
99     *
100     * @param url the single URL to load classes from.
101     * @param origURL the possibly null original URL from which url may
102     * be a local copy or nested jar.
103     * @param parent the parent class loader to use
104     */

105    public UnifiedClassLoader(URL JavaDoc url, URL JavaDoc origURL, ClassLoader JavaDoc parent)
106    {
107       super(url == null ? new URL JavaDoc[]{} : new URL JavaDoc[] {url}, parent);
108
109       if (log.isTraceEnabled())
110          log.trace("New jmx UCL with url " + url);
111       this.url = url;
112       this.origURL = origURL;
113    }
114
115    /**
116     * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
117     * repository.
118     *
119     * @param url The single URL to load classes from.
120     * @param repository the repository this classloader delegates to
121     */

122    public UnifiedClassLoader(URL JavaDoc url, LoaderRepository repository)
123    {
124       this(url, null, repository);
125    }
126    /**
127     * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
128     * repository.
129     * @param url The single URL to load classes from.
130     * @param origURL the possibly null original URL from which url may
131     * be a local copy or nested jar.
132     * @param repository the repository this classloader delegates to
133     * be a local copy or nested jar.
134     */

135    public UnifiedClassLoader(URL JavaDoc url, URL JavaDoc origURL, LoaderRepository repository)
136    {
137       this(url, origURL);
138
139       // set the repository reference
140
this.setRepository(repository);
141
142       // register this loader to the given repository
143
repository.addClassLoader(this);
144    }
145
146    /**
147     * UnifiedClassLoader constructor that can be used to
148     * register with a particular Loader Repository identified by ObjectName.
149     *
150     * @param url an <code>URL</code> value
151     * @param server a <code>MBeanServer</code> value
152     * @param repositoryName an <code>ObjectName</code> value
153     * @exception Exception if an error occurs
154     */

155    public UnifiedClassLoader(final URL JavaDoc url, final MBeanServer JavaDoc server,
156       final ObjectName JavaDoc repositoryName) throws Exception JavaDoc
157    {
158       this(url, null, server, repositoryName);
159    }
160    /**
161     * UnifiedClassLoader constructor that can be used to
162     * register with a particular Loader Repository identified by ObjectName.
163     *
164     * @param url an <code>URL</code> value
165     * @param origURL the possibly null original URL from which url may
166     * be a local copy or nested jar.
167     * @param server a <code>MBeanServer</code> value
168     * @param repositoryName an <code>ObjectName</code> value
169     * @exception Exception if an error occurs
170     */

171    public UnifiedClassLoader(final URL JavaDoc url, final URL JavaDoc origURL,
172       final MBeanServer JavaDoc server, final ObjectName JavaDoc repositoryName) throws Exception JavaDoc
173    {
174       this(url, origURL);
175       LoaderRepository rep = (LoaderRepository)server.invoke(repositoryName,
176                     "registerClassLoader",
177                     new Object JavaDoc[] {this},
178                     new String JavaDoc[] {getClass().getName()});
179       this.setRepository(rep);
180    }
181
182    // Public --------------------------------------------------------
183

184    /** Obtain the ObjectName under which the UCL can be registered with the
185     JMX server. This creates a name of the form "jmx.loading:UCL=hashCode"
186     since we don't currently care that UCL be easily queriable.
187     */

188    public ObjectName JavaDoc getObjectName() throws MalformedObjectNameException JavaDoc
189    {
190       String JavaDoc name = "jmx.loading:UCL="+Integer.toHexString(super.hashCode());
191       return new ObjectName JavaDoc(name);
192    }
193
194    public void unregister()
195    {
196       super.unregister();
197       this.origURL = null;
198       this.url = null;
199    }
200
201    /** Get the URL associated with the UCL.
202     */

203    public URL JavaDoc getURL()
204    {
205       return url;
206    }
207    
208    /** Get the original URL associated with the UCL. This may be null.
209     */

210    public URL JavaDoc getOrigURL()
211    {
212       return origURL;
213    }
214    
215    public synchronized Class JavaDoc loadClassImpl(String JavaDoc name, boolean resolve, int stopAt)
216       throws ClassNotFoundException JavaDoc
217    {
218       loadClassDepth ++;
219       boolean trace = log.isTraceEnabled();
220
221       if( trace )
222          log.trace("loadClassImpl, name="+name+", resolve="+resolve);
223       if( repository == null )
224       {
225          // If we have been undeployed we can still try locally
226
try
227          {
228             return super.loadClass(name, resolve);
229          }
230          catch (ClassNotFoundException JavaDoc ignored)
231          {
232          }
233          String JavaDoc msg = "Invalid use of destroyed classloader, UCL destroyed at:";
234          throw new ClassNotFoundException JavaDoc(msg, this.unregisterTrace);
235       }
236
237       /* Since loadClass can be called from loadClassInternal with the monitor
238          already held, we need to determine if there is a ClassLoadingTask
239          which requires this UCL. If there is, we release the UCL monitor
240          so that the ClassLoadingTask can use the UCL.
241        */

242       boolean acquired = attempt(1);
243       while( acquired == false )
244       {
245          /* Another thread needs this UCL to load a class so release the
246           monitor acquired by the synchronized method. We loop until
247           we can acquire the class loading lock.
248          */

249         try
250          {
251             if( trace )
252                log.trace("Waiting for loadClass lock");
253             this.wait();
254          }
255          catch(InterruptedException JavaDoc ignore)
256          {
257          }
258          acquired = attempt(1);
259       }
260
261       ClassLoadingTask task = null;
262       try
263       {
264          Thread JavaDoc t = Thread.currentThread();
265          // Register this thread as owning this UCL
266
if( loadLock.holds() == 1 )
267             LoadMgr3.registerLoaderThread(this, t);
268
269          // Create a class loading task and submit it to the repository
270
task = new ClassLoadingTask(name, this, t, stopAt);
271          /* Process class loading tasks needing this UCL until our task has
272             been completed by the thread owning the required UCL(s).
273           */

274          UnifiedLoaderRepository3 ulr3 = (UnifiedLoaderRepository3) repository;
275          if( LoadMgr3.beginLoadTask(task, ulr3) == false )
276          {
277             while( task.threadTaskCount != 0 )
278             {
279                try
280                {
281                   LoadMgr3.nextTask(t, task, ulr3);
282                }
283                catch(InterruptedException JavaDoc e)
284                {
285                   // Abort the load or retry?
286
break;
287                }
288             }
289          }
290       }
291       finally
292       {
293          // Unregister as the UCL owner to reschedule any remaining load tasks
294
if( loadLock.holds() == 1 )
295             LoadMgr3.endLoadTask(task);
296          // Notify any threads waiting to use this UCL
297
this.release();
298          this.notifyAll();
299          loadClassDepth --;
300       }
301
302       if( task.loadedClass == null )
303       {
304          if( task.loadException instanceof ClassNotFoundException JavaDoc )
305             throw (ClassNotFoundException JavaDoc) task.loadException;
306          else if( task.loadException instanceof NoClassDefFoundError JavaDoc )
307             throw (NoClassDefFoundError JavaDoc) task.loadException;
308          else if( task.loadException != null )
309          {
310             if( log.isTraceEnabled() )
311                log.trace("Unexpected error during load of:"+name, task.loadException);
312             String JavaDoc msg = "Unexpected error during load of: "+name
313                + ", msg="+task.loadException.getMessage();
314             ClassNotFoundException JavaDoc cnfe = new ClassNotFoundException JavaDoc(msg, task.loadException);
315             throw cnfe;
316          }
317          // Assert that loadedClass is not null
318
else
319             throw new IllegalStateException JavaDoc("ClassLoadingTask.loadedTask is null, name: "+name);
320       }
321
322       return task.loadedClass;
323    }
324
325    // URLClassLoader overrides --------------------------------------
326

327    /** Override the permissions accessor to use the CodeSource
328     based on the original URL if one exists. This allows the
329     security policy to be defined in terms of the static URL
330     namespace rather than the local copy or nested URL.
331     This builds a PermissionCollection from:
332     1. The origURL CodeSource
333     2. The argument CodeSource
334     3. The Policy.getPermission(origURL CodeSource)
335
336     This is necessary because we cannot define the CodeSource the
337     SecureClassLoader uses to register the class under.
338
339     @param cs the location and signatures of the codebase.
340     */

341    protected PermissionCollection JavaDoc getPermissions(CodeSource JavaDoc cs)
342    {
343       CodeSource JavaDoc permCS = cs;
344       if( origURL != null )
345       {
346          permCS = new CodeSource JavaDoc(origURL, cs.getCertificates());
347       }
348       Policy JavaDoc policy = Policy.getPolicy();
349       PermissionCollection JavaDoc perms = super.getPermissions(permCS);
350       PermissionCollection JavaDoc perms2 = super.getPermissions(cs);
351       PermissionCollection JavaDoc perms3 = policy.getPermissions(permCS);
352       Enumeration JavaDoc iter = perms2.elements();
353       while( iter.hasMoreElements() )
354          perms.add((Permission JavaDoc) iter.nextElement());
355       iter = perms3.elements();
356       while( iter.hasMoreElements() )
357          perms.add((Permission JavaDoc) iter.nextElement());
358       if( log.isTraceEnabled() )
359          log.trace("getPermissions, url="+url+", origURL="+origURL+" -> "+perms);
360       return perms;
361    }
362
363    /**
364     * Determine the protection domain. If we are a copy of the original
365     * deployment, use the original url as the codebase.
366     * @return the protection domain
367     * @todo certificates and principles?
368     */

369    protected ProtectionDomain JavaDoc getProtectionDomain()
370    {
371       return getProtectionDomain(origURL != null ? origURL : url);
372    }
373 }
374
Popular Tags