Get ClassLoader within doPrivileged().
[guacamole.git] / src / main / java / net / sourceforge / guacamole / net / basic / GuacamoleClassLoader.java
1
2 package net.sourceforge.guacamole.net.basic;
3
4 /* ***** BEGIN LICENSE BLOCK *****
5  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is guacamole-common.
18  *
19  * The Initial Developer of the Original Code is
20  * Michael Jumper.
21  * Portions created by the Initial Developer are Copyright (C) 2010
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Alternatively, the contents of this file may be used under the terms of
27  * either the GNU General Public License Version 2 or later (the "GPL"), or
28  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29  * in which case the provisions of the GPL or the LGPL are applicable instead
30  * of those above. If you wish to allow use of your version of this file only
31  * under the terms of either the GPL or the LGPL, and not to allow others to
32  * use your version of this file under the terms of the MPL, indicate your
33  * decision by deleting the provisions above and replace them with the notice
34  * and other provisions required by the GPL or the LGPL. If you do not delete
35  * the provisions above, a recipient may use your version of this file under
36  * the terms of any one of the MPL, the GPL or the LGPL.
37  *
38  * ***** END LICENSE BLOCK ***** */
39
40 import java.io.File;
41 import java.io.FilenameFilter;
42 import java.net.MalformedURLException;
43 import java.net.URL;
44 import java.net.URLClassLoader;
45 import java.security.AccessController;
46 import java.security.PrivilegedActionException;
47 import java.security.PrivilegedExceptionAction;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import net.sourceforge.guacamole.GuacamoleException;
51 import net.sourceforge.guacamole.net.basic.properties.BasicGuacamoleProperties;
52 import net.sourceforge.guacamole.properties.GuacamoleProperties;
53
54 /**
55  * A ClassLoader implementation which finds classes within a configurable
56  * directory. This directory is set within guacamole.properties.
57  * 
58  * @author Michael Jumper
59  */
60 public class GuacamoleClassLoader extends ClassLoader {
61     
62     private URLClassLoader classLoader = null;
63
64     private static GuacamoleException exception = null;
65     private static GuacamoleClassLoader instance = null;
66     
67     static {
68         
69         try {
70             // Attempt to create singleton classloader which loads classes from
71             // all .jar's in the lib directory defined in guacamole.properties
72             instance = AccessController.doPrivileged(new PrivilegedExceptionAction<GuacamoleClassLoader>() {
73
74                 @Override
75                 public GuacamoleClassLoader run() throws GuacamoleException {
76                     return new GuacamoleClassLoader(
77                         GuacamoleProperties.getProperty(BasicGuacamoleProperties.LIB_DIRECTORY)
78                     );
79                 }
80
81             });
82         }
83         
84         catch (PrivilegedActionException e) {
85             // On error, record exception
86             exception = (GuacamoleException) e.getException();
87         }
88         
89     }
90
91     private GuacamoleClassLoader(File libDirectory) throws GuacamoleException {
92
93         // If no directory provided, just direct requests to parent classloader
94         if (libDirectory == null)
95             return;
96         
97         // Validate directory is indeed a directory
98         if (!libDirectory.isDirectory())
99             throw new GuacamoleException(libDirectory + " is not a directory.");
100         
101         // Get list of URLs for all .jar's in the lib directory
102         Collection<URL> jarURLs = new ArrayList<URL>();
103         for (File file : libDirectory.listFiles(new FilenameFilter() {
104
105             @Override
106             public boolean accept(File dir, String name) {
107                 
108                 // If it ends with .jar, accept the file
109                 return name.endsWith(".jar");
110                 
111             }
112
113         })) {
114
115             try {
116                 
117                 // Add URL for the .jar to the jar URL list
118                 jarURLs.add(file.toURI().toURL());
119                 
120             }
121             catch (MalformedURLException e) {
122                 throw new GuacamoleException(e);
123             }
124                 
125         }
126         
127         // Set delegate classloader to new URLClassLoader which loads from the
128         // .jars found above.
129
130         URL[] urls = new URL[jarURLs.size()];
131         classLoader = new URLClassLoader(
132             jarURLs.toArray(urls),
133             getClass().getClassLoader()
134         );
135         
136     }
137
138     /**
139      * Returns an instance of a GuacamoleClassLoader which finds classes
140      * within the directory configured in guacamole.properties.
141      * 
142      * @return An instance of a GuacamoleClassLoader.
143      * @throws GuacamoleException If no instance could be returned due to an
144      *                            error.
145      */
146     public static GuacamoleClassLoader getInstance() throws GuacamoleException {
147         
148         // If instance could not be created, rethrow original exception
149         if (exception != null) throw exception;
150         
151         return instance;
152
153     }
154
155     @Override
156     protected Class<?> findClass(String name) throws ClassNotFoundException {
157
158         // If no classloader, use default loader
159         if (classLoader == null)
160             return Class.forName(name);
161         
162         // Otherwise, delegate
163         return classLoader.loadClass(name);
164
165     }
166
167 }