mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-30 00:23:21 +00:00 
			
		
		
		
	GUACAMOLE-541: Prioritize classes defined within extensions over classes inherited from the webapp classpath or lib directory.
This commit is contained in:
		| @@ -21,12 +21,6 @@ package org.apache.guacamole.extension; | |||||||
|  |  | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.net.MalformedURLException; |  | ||||||
| import java.net.URL; |  | ||||||
| import java.net.URLClassLoader; |  | ||||||
| import java.security.AccessController; |  | ||||||
| import java.security.PrivilegedActionException; |  | ||||||
| import java.security.PrivilegedExceptionAction; |  | ||||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||||
| import java.util.Collection; | import java.util.Collection; | ||||||
| import java.util.Collections; | import java.util.Collections; | ||||||
| @@ -387,34 +381,8 @@ public class Extension { | |||||||
|                 extension.close(); |                 extension.close(); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             try { |  | ||||||
|  |  | ||||||
|             // Create isolated classloader for this extension |             // Create isolated classloader for this extension | ||||||
|                 classLoader = AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>() { |             classLoader = ExtensionClassLoader.getInstance(file, parent); | ||||||
|  |  | ||||||
|                     @Override |  | ||||||
|                     public ClassLoader run() throws GuacamoleException { |  | ||||||
|  |  | ||||||
|                         try { |  | ||||||
|  |  | ||||||
|                             // Classloader must contain only the extension itself |  | ||||||
|                             return new URLClassLoader(new URL[]{file.toURI().toURL()}, parent); |  | ||||||
|  |  | ||||||
|                         } |  | ||||||
|                         catch (MalformedURLException e) { |  | ||||||
|                             throw new GuacamoleException(e); |  | ||||||
|                         } |  | ||||||
|  |  | ||||||
|                     } |  | ||||||
|  |  | ||||||
|                 }); |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             // Rethrow any GuacamoleException |  | ||||||
|             catch (PrivilegedActionException e) { |  | ||||||
|                 throw (GuacamoleException) e.getException(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|         } |         } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,159 @@ | |||||||
|  | /* | ||||||
|  |  * Licensed to the Apache Software Foundation (ASF) under one | ||||||
|  |  * or more contributor license agreements.  See the NOTICE file | ||||||
|  |  * distributed with this work for additional information | ||||||
|  |  * regarding copyright ownership.  The ASF licenses this file | ||||||
|  |  * to you under the Apache License, Version 2.0 (the | ||||||
|  |  * "License"); you may not use this file except in compliance | ||||||
|  |  * with the License.  You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, | ||||||
|  |  * software distributed under the License is distributed on an | ||||||
|  |  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||||
|  |  * KIND, either express or implied.  See the License for the | ||||||
|  |  * specific language governing permissions and limitations | ||||||
|  |  * under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | package org.apache.guacamole.extension; | ||||||
|  |  | ||||||
|  | import java.io.File; | ||||||
|  | import java.net.MalformedURLException; | ||||||
|  | import java.net.URL; | ||||||
|  | import java.net.URLClassLoader; | ||||||
|  | import java.security.AccessController; | ||||||
|  | import java.security.PrivilegedActionException; | ||||||
|  | import java.security.PrivilegedExceptionAction; | ||||||
|  | import org.apache.guacamole.GuacamoleException; | ||||||
|  | import org.apache.guacamole.GuacamoleServerException; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * ClassLoader implementation which prioritizes the classes defined within a | ||||||
|  |  * given extension .jar file. Unlike the standard URLClassLoader, classes | ||||||
|  |  * within the parent ClassLoader are only used if they are not defined within | ||||||
|  |  * the given .jar. If classes are defined in both the parent and the extension | ||||||
|  |  * .jar, the versions defined within the extension .jar are used. | ||||||
|  |  */ | ||||||
|  | public class ExtensionClassLoader extends URLClassLoader { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * The ClassLoader to use if class resolution through the extension .jar | ||||||
|  |      * fails. | ||||||
|  |      */ | ||||||
|  |     private final ClassLoader parent; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns an instance of ExtensionClassLoader configured to load classes | ||||||
|  |      * from the given extension .jar. If a necessary class cannot be found | ||||||
|  |      * within the .jar, the given parent ClassLoader is used. Calling this | ||||||
|  |      * function multiple times will not affect previously-returned instances of | ||||||
|  |      * ExtensionClassLoader. | ||||||
|  |      * | ||||||
|  |      * @param extension | ||||||
|  |      *     The extension .jar file from which classes should be loaded. | ||||||
|  |      * | ||||||
|  |      * @param parent | ||||||
|  |      *     The ClassLoader to use if class resolution through the extension | ||||||
|  |      *     .jar fails. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A ExtensionClassLoader instance which loads classes from the | ||||||
|  |      *     given extension .jar file. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If the given file is not actually a file, or the contents of the | ||||||
|  |      *     file cannot be read. | ||||||
|  |      */ | ||||||
|  |     public static ExtensionClassLoader getInstance(final File extension, | ||||||
|  |             final ClassLoader parent) throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             // Attempt to create classloader which loads classes from the given | ||||||
|  |             // .jar file | ||||||
|  |             return AccessController.doPrivileged(new PrivilegedExceptionAction<ExtensionClassLoader>() { | ||||||
|  |  | ||||||
|  |                 @Override | ||||||
|  |                 public ExtensionClassLoader run() throws GuacamoleException { | ||||||
|  |                     return new ExtensionClassLoader(extension, parent); | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         catch (PrivilegedActionException e) { | ||||||
|  |             throw (GuacamoleException) e.getException(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Returns a URL which points to the given extension .jar file. | ||||||
|  |      * | ||||||
|  |      * @param extension | ||||||
|  |      *     The extension .jar file to generate a URL for. | ||||||
|  |      * | ||||||
|  |      * @return | ||||||
|  |      *     A URL which points to the given extension .jar. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If the given file is not actually a file, or the contents of the | ||||||
|  |      *     file cannot be read. | ||||||
|  |      */ | ||||||
|  |     private static URL getExtensionURL(File extension) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |  | ||||||
|  |         // Validate extension file is indeed a file | ||||||
|  |         if (!extension.isFile()) | ||||||
|  |             throw new GuacamoleException(extension + " is not a file."); | ||||||
|  |  | ||||||
|  |         try { | ||||||
|  |             return extension.toURI().toURL(); | ||||||
|  |         } | ||||||
|  |         catch (MalformedURLException e) { | ||||||
|  |             throw new GuacamoleServerException(e); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Creates a new ExtensionClassLoader configured to load classes from the | ||||||
|  |      * given extension .jar. If a necessary class cannot be found within the | ||||||
|  |      * .jar, the given parent ClassLoader is used. Calling this function | ||||||
|  |      * multiple times will not affect previously-returned instances of | ||||||
|  |      * ExtensionClassLoader. | ||||||
|  |      * | ||||||
|  |      * @param extension | ||||||
|  |      *     The extension .jar file from which classes should be loaded. | ||||||
|  |      * | ||||||
|  |      * @param parent | ||||||
|  |      *     The ClassLoader to use if class resolution through the extension | ||||||
|  |      *     .jar fails. | ||||||
|  |      * | ||||||
|  |      * @throws GuacamoleException | ||||||
|  |      *     If the given file is not actually a file, or the contents of the | ||||||
|  |      *     file cannot be read. | ||||||
|  |      */ | ||||||
|  |     private ExtensionClassLoader(File extension, ClassLoader parent) | ||||||
|  |             throws GuacamoleException { | ||||||
|  |         super(new URL[]{ getExtensionURL(extension) }, null); | ||||||
|  |         this.parent = parent; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     protected Class<?> findClass(String string) throws ClassNotFoundException { | ||||||
|  |  | ||||||
|  |         // Search only within the given URLs | ||||||
|  |         try { | ||||||
|  |             return super.findClass(string); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         // Search parent classloader ONLY if not found within given URLs | ||||||
|  |         catch (ClassNotFoundException e) { | ||||||
|  |             return parent.loadClass(string); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user