001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.loading;
023:
024: import java.net.URL;
025: import java.security.CodeSource;
026: import java.security.Permission;
027: import java.security.PermissionCollection;
028: import java.security.Policy;
029: import java.security.ProtectionDomain;
030: import java.util.Enumeration;
031:
032: import javax.management.MBeanServer;
033: import javax.management.MalformedObjectNameException;
034: import javax.management.ObjectName;
035:
036: import org.jboss.logging.Logger;
037: import org.jboss.util.loading.Translatable;
038:
039: /**
040: * A ClassLoader which loads classes from a single URL in conjunction with
041: * the {@link LoaderRepository}. Notice that this classloader does
042: * not work independently of the repository. A repository reference
043: * must be provided via the constructor or the classloader must be explicitly
044: * registered to the repository before any attempt to load a class.
045: *
046: * At this point this is little more than an abstract class maintained as the
047: * interface for class loaders as the algorithm of the UnifiedLoaderRepository
048: * fails with deadlocks, and several other class loading exceptions in multi-
049: * threaded environments.
050: *
051: * @author <a href="marc.fleury@jboss.org">Marc Fleury</a>
052: * @author <a href="christoph.jung@jboss.org">Christoph G. Jung</a>
053: * @author <a href="scott.stark@jboss.org">Scott Stark</a>
054: * @author <a href="juha@jboss.org">Juha Lindfors</a>
055: * @author <a href="bill@jboss.org">Bill Burke</a>
056: * @version <tt>$Revision: 57200 $</tt>
057: */
058: public class UnifiedClassLoader extends RepositoryClassLoader implements
059: UnifiedClassLoaderMBean, Translatable {
060: // Static --------------------------------------------------------
061:
062: private static final Logger log = Logger
063: .getLogger(UnifiedClassLoader.class);
064:
065: // Attributes ----------------------------------------------------
066:
067: /** One URL per ClassLoader in our case */
068: protected URL url = null;
069: /** An optional URL from which url may have been copied. It is used to
070: allow the security permissions to be based on a static url namespace. */
071: protected URL origURL = null;
072:
073: // Constructors --------------------------------------------------
074: /**
075: * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
076: * classloader repository.
077: *
078: * @param url the single URL to load classes from.
079: */
080: public UnifiedClassLoader(URL url) {
081: this (url, (URL) null);
082: }
083:
084: /**
085: * Construct a <tt>UnifiedClassLoader</tt> without registering it to the
086: * classloader repository.
087: *
088: * @param url the single URL to load classes from.
089: * @param origURL the possibly null original URL from which url may
090: * be a local copy or nested jar.
091: */
092: public UnifiedClassLoader(URL url, URL origURL) {
093: this (url, origURL, UnifiedClassLoader.class.getClassLoader());
094: }
095:
096: /** Construct a UnifiedClassLoader without registering with the
097: * classloader repository.
098: *
099: * @param url the single URL to load classes from.
100: * @param origURL the possibly null original URL from which url may
101: * be a local copy or nested jar.
102: * @param parent the parent class loader to use
103: */
104: public UnifiedClassLoader(URL url, URL origURL, ClassLoader parent) {
105: super (url == null ? new URL[] {} : new URL[] { url }, parent);
106:
107: if (log.isTraceEnabled())
108: log.trace("New jmx UCL with url " + url);
109: this .url = url;
110: this .origURL = origURL;
111: }
112:
113: /**
114: * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
115: * repository.
116: *
117: * @param url The single URL to load classes from.
118: * @param repository the repository this classloader delegates to
119: */
120: public UnifiedClassLoader(URL url, LoaderRepository repository) {
121: this (url, null, repository);
122: }
123:
124: /**
125: * Construct a <tt>UnifiedClassLoader</tt> and registers it to the given
126: * repository.
127: * @param url The single URL to load classes from.
128: * @param origURL the possibly null original URL from which url may
129: * be a local copy or nested jar.
130: * @param repository the repository this classloader delegates to
131: * be a local copy or nested jar.
132: */
133: public UnifiedClassLoader(URL url, URL origURL,
134: LoaderRepository repository) {
135: this (url, origURL);
136:
137: // set the repository reference
138: this .setRepository(repository);
139:
140: // register this loader to the given repository
141: repository.addClassLoader(this );
142: }
143:
144: /**
145: * UnifiedClassLoader constructor that can be used to
146: * register with a particular Loader Repository identified by ObjectName.
147: *
148: * @param url an <code>URL</code> value
149: * @param server a <code>MBeanServer</code> value
150: * @param repositoryName an <code>ObjectName</code> value
151: * @exception Exception if an error occurs
152: */
153: public UnifiedClassLoader(final URL url, final MBeanServer server,
154: final ObjectName repositoryName) throws Exception {
155: this (url, null, server, repositoryName);
156: }
157:
158: /**
159: * UnifiedClassLoader constructor that can be used to
160: * register with a particular Loader Repository identified by ObjectName.
161: *
162: * @param url an <code>URL</code> value
163: * @param origURL the possibly null original URL from which url may
164: * be a local copy or nested jar.
165: * @param server a <code>MBeanServer</code> value
166: * @param repositoryName an <code>ObjectName</code> value
167: * @exception Exception if an error occurs
168: */
169: public UnifiedClassLoader(final URL url, final URL origURL,
170: final MBeanServer server, final ObjectName repositoryName)
171: throws Exception {
172: this (url, origURL);
173: LoaderRepository rep = (LoaderRepository) server.invoke(
174: repositoryName, "registerClassLoader",
175: new Object[] { this }, new String[] { getClass()
176: .getName() });
177: this .setRepository(rep);
178: }
179:
180: // Public --------------------------------------------------------
181:
182: /** Obtain the ObjectName under which the UCL can be registered with the
183: JMX server. This creates a name of the form "jmx.loading:UCL=hashCode"
184: since we don't currently care that UCL be easily queriable.
185: */
186: public ObjectName getObjectName()
187: throws MalformedObjectNameException {
188: String name = "jmx.loading:UCL="
189: + Integer.toHexString(super .hashCode());
190: return new ObjectName(name);
191: }
192:
193: public void unregister() {
194: super .unregister();
195: this .origURL = null;
196: this .url = null;
197: }
198:
199: /** Get the URL associated with the UCL.
200: */
201: public URL getURL() {
202: return url;
203: }
204:
205: /** Get the original URL associated with the UCL. This may be null.
206: */
207: public URL getOrigURL() {
208: return origURL;
209: }
210:
211: // URLClassLoader overrides --------------------------------------
212:
213: /** Override the permissions accessor to use the CodeSource
214: based on the original URL if one exists. This allows the
215: security policy to be defined in terms of the static URL
216: namespace rather than the local copy or nested URL.
217: This builds a PermissionCollection from:
218: 1. The origURL CodeSource
219: 2. The argument CodeSource
220: 3. The Policy.getPermission(origURL CodeSource)
221:
222: This is necessary because we cannot define the CodeSource the
223: SecureClassLoader uses to register the class under.
224:
225: @param cs the location and signatures of the codebase.
226: */
227: protected PermissionCollection getPermissions(CodeSource cs) {
228: CodeSource permCS = cs;
229: if (origURL != null) {
230: permCS = new CodeSource(origURL, cs.getCertificates());
231: }
232: Policy policy = Policy.getPolicy();
233: PermissionCollection perms = super .getPermissions(permCS);
234: PermissionCollection perms2 = super .getPermissions(cs);
235: PermissionCollection perms3 = policy.getPermissions(permCS);
236: Enumeration iter = perms2.elements();
237: while (iter.hasMoreElements())
238: perms.add((Permission) iter.nextElement());
239: iter = perms3.elements();
240: while (iter.hasMoreElements())
241: perms.add((Permission) iter.nextElement());
242: if (log.isTraceEnabled())
243: log.trace("getPermissions, url=" + url + ", origURL="
244: + origURL + " -> " + perms);
245: return perms;
246: }
247:
248: /**
249: * Determine the protection domain. If we are a copy of the original
250: * deployment, use the original url as the codebase.
251: * @return the protection domain
252: * @todo certificates and principles?
253: */
254: protected ProtectionDomain getProtectionDomain() {
255: return getProtectionDomain(origURL != null ? origURL : url);
256: }
257: }
|