Thanks Chuck for your reply.

I still think it is a bug!!! 

Please try the following: add a jar file (eg, foo/bar.jar) as a class 
repository in the catalina.properties and then use one of the classes from this 
jar file in one the servlets - will get a ClassNotFoundException.

I've attached ClassLoaderFactoryTest.java and 
ClassLoaderFactoryWithTheFix.java. Please try to run the test - one of the 
tests will fail, refer to the place where it fails and read the comments.


Kind regards,

Alex.



-----Original Message-----
From: Caldarale, Charles R [mailto:[EMAIL PROTECTED]
Sent: Thursday, 21 April 2005 9:27 PM
To: Tomcat Users List
Subject: RE: Problem with the classloader in jakarta-tomcat-5.0.28 -
cannot add a jar file to class repository


> From: Akoulov, Alexandre [IT] [mailto:[EMAIL PROTECTED]

> Subject: Problem with the classloader in 
> jakarta-tomcat-5.0.28 - cannot add a jar file to class repository
> 
> ClassLoaderFactory#createClassLoader(File unpacked[], File 
> packed[], URL urls[], ClassLoader parent) is the actual 
> method that creates class loaders. The very first argument to 
> this method contains jar files or directories ( that is where 
> the name "unpacked" comes from ). 

>From what I can tell, it's the _second_ argument that should contain
.jar files; the first is for directories only.

 - Chuck


THIS COMMUNICATION MAY CONTAIN CONFIDENTIAL AND/OR OTHERWISE PROPRIETARY
MATERIAL and is thus for use only by the intended recipient. If you
received this in error, please contact the sender and delete the e-mail
and its attachments from all computers.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]




-----Original Message-----
From: Akoulov, Alexandre [IT] 
Sent: Thursday, 21 April 2005 6:29 PM
To: [email protected]
Subject: Problem with the classloader in jakarta-tomcat-5.0.28 - cannot
add a jar file to class repository


Hi all,

I'd greatly appreciate your thoughts on the following issue (and the proposed 
solution ):



When adding a jar file (eg, "foo/bar.jar") to the class loader's repository it 
treats as a directory and therefore it cannot load any classes from this jar. 
The following explains why it happens.
        
org.apache.catalina.startup.ClassLoaderFactory is responsible for creating 
class loader instances. Each instance is of 
org.apache.catalina.loader.StandardClassLoader type, which in its turn extends 
java.net.URLClassLoader:
-----------------------------------------------------------------------------
                        public class StandardClassLoader extends URLClassLoader
-----------------------------------------------------------------------------
        
ClassLoaderFactory#createClassLoader(File unpacked[], File packed[], URL 
urls[], ClassLoader parent) is the actual method that creates class loaders. 
The very first argument to this method contains jar files or directories ( that 
is where the name "unpacked" comes from ). 
        
ClassLoaderFactory#createClassLoader method adds File.separator to the end of 
the jar file path ( file.getCanonicalPath() + File.separator ) when 
constructing a URL instance to represent a jar file and then adds a string 
representation of a newly created URL to its list of repositories ( 
list.add(url.toString()) ) :
-----------------------------------------------------------------------------
                        if (unpacked != null) {
                for (int i = 0; i < unpacked.length; i++)  {
                        File file = unpacked[i];
                        if (!file.exists() || !file.canRead())
                            continue;
                        if (debug >= 1)
                            log("  Including directory or JAR " 
                                + file.getAbsolutePath());
                        URL url = new URL("file", null,
                                          file.getCanonicalPath() + 
File.separator);
                        list.add(url.toString());
                    }
                }
-----------------------------------------------------------------------------
                
For instance, if "unpacked"     argument contains '/home/aa/lib/velocity.jar' 
then a URL object is 'file:/home/aa/lib/velocity.jar/' - a forward slash / 
(which is a Unix file separator) has been added to the url.
        
After ClassLoaderFactory#createClassLoader adds all repositories to its 
repository list it converts this list to array and constructs 
StandardClassLoader with it:
        
-----------------------------------------------------------------------------
                        String array[] = (String[]) list.toArray(new 
String[list.size()]);
                StandardClassLoader classLoader = null;
                if (parent == null)
                    classLoader = new StandardClassLoader(array);
-----------------------------------------------------------------------------
            
StandardClassLoader( String[] ) constructor converts each repository found in 
the given array argument to a URL object:
-----------------------------------------------------------------------------
                    protected static URL[] convert(String input[], 
URLStreamHandlerFactory factory) {
                        .....
                        url[i] = new URL(null, input[i], streamHandler);
                        .....
                    }
-----------------------------------------------------------------------------
                                   
For instance, if the repositories array of String type contains 
'file:/home/aa/lib/velocity.jar/' then a URL object is 
'file:/home/aa/lib/velocity.jar/'. If the repository holds a path on Windows 
machine then the URL object would have all backslashes  replaced all  with 
forward slashes ( URL object crated with new URL(null, 
"file:I:\lib\velocity.jar\", streamHandler) would have 
"file:I:/lib/velocity.jar/" string representation ).
    
Once StandardClassLoader( String[] ) converts repository array of a String type 
into a URL type it calls its super constructor, which in fact is a 
URLClassLoader( URL[] ).
    
However, the contract for URLClassLoader( URL[] ) constructor indicates that 
"Any URL that ends with a '/' is assumed to refer to a directory. " and 
therefore a jar file gets ignored by the loader.
    
For instance, if the repositories array contains 
'file:/home/aa/lib/velocity.jar/' url object the URLClassLoader( URL[] ) 
constructor treats this url as a directory and therefore a jar file is never 
properly loaded.
    
    
Therefore, a File.separator that got added to a jar file in 
ClassLoaderFactory#createClassLoader method made it invalid because the actual 
class loader assumes that this jar file is a directory.
    
==================================================    
Proposed solution
==================================================

ClassLoaderFactory#createClassLoader(File unpacked[], File packed[], URL 
urls[], ClassLoader parent) is to be modified so that it does not add 
File.separator to the end of jar files found in the unpacked argument:
     
-----------------------------------------------------------------------------
                        if (unpacked != null) {
                for (int i = 0; i < unpacked.length; i++)  {
                        File file = unpacked[i];
                        if (!file.exists() || !file.canRead())
                            continue;
                        if (debug >= 1)
                            log("  Including directory or JAR " 
                                + file.getAbsolutePath());
                        
                        // THE FIX
                        StringBuffer filePath = new 
StringBuffer(file.getCanonicalPath());
                        if ( file.isDirectory() ) { 
                                // Only add a file separator if a file 
represents a directory
                                filePath.append(File.separator);
                        }
                                        
                        URL url = new URL("file", null, filePath.toString());
                        list.add(url.toString());
                    }
                }       
-----------------------------------------------------------------------------
                        
        


Kind regards,

Alex.
        

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to