Return-Path: Delivered-To: apmail-jakarta-tomcat-user-archive@www.apache.org Received: (qmail 68254 invoked from network); 22 Apr 2005 00:49:49 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 22 Apr 2005 00:49:49 -0000 Received: (qmail 80750 invoked by uid 500); 22 Apr 2005 00:49:39 -0000 Delivered-To: apmail-jakarta-tomcat-user-archive@jakarta.apache.org Received: (qmail 80726 invoked by uid 500); 22 Apr 2005 00:49:38 -0000 Mailing-List: contact tomcat-user-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Tomcat Users List" Reply-To: "Tomcat Users List" Delivered-To: mailing list tomcat-user@jakarta.apache.org Received: (qmail 80712 invoked by uid 99); 22 Apr 2005 00:49:38 -0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: pass (hermes.apache.org: domain of alexandre.akoulov@citigroup.com designates 199.67.203.181 as permitted sender) Received: from smtp3.citigroup.com (HELO mail.citigroup.com) (199.67.203.181) by apache.org (qpsmtpd/0.28) with ESMTP; Thu, 21 Apr 2005 17:49:38 -0700 Received: from imbarc-ny01.ny.ssmb.com (imbarc-ny01.ny.ssmb.com [162.124.186.138]) by imbaspam-eu04.eur.nsroot.net (8.13.1/8.13.1/SSMB_EXT/ev: 11565 $) with ESMTP id j3M0mjwm003260 for ; Fri, 22 Apr 2005 00:49:00 GMT Received: from mailhub-au01.aus.nsroot.net (mailhub-au01.aus.nsroot.net [169.191.97.43]) by imbarc-ny01.ny.ssmb.com (8.13.1/8.13.1/SSMB_QQQ_IN/1.1) with ESMTP id j3M0mLl0005973 for ; Fri, 22 Apr 2005 00:48:21 GMT Received: from exmesm01.aus.nsroot.net (prkbigip1-11-1-int0.aus.nsroot.net [169.191.97.129]) by mailhub-au01.aus.nsroot.net (8.12.10/8.12.10/CG_HUB) with ESMTP id j3M0mJ47010119 for ; Fri, 22 Apr 2005 00:48:20 GMT Received: from exsymb02.aus.nsroot.net ([169.191.99.130]) by exmesm01.aus.nsroot.net with Microsoft SMTPSVC(5.0.2195.6713); Fri, 22 Apr 2005 10:48:19 +1000 X-MimeOLE: Produced By Microsoft Exchange V6.0.6603.0 content-class: urn:content-classes:message MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----_=_NextPart_001_01C546D4.FA17F8D6" Subject: RE: Problem with the classloader in jakarta-tomcat-5.0.28 - cannot add a jar file to class repository Date: Fri, 22 Apr 2005 10:48:19 +1000 Message-ID: <1F78B75C252B574FBC551990AE8A836702EE105A@exsymb02.aus.nsroot.net> X-MS-Has-Attach: yes X-MS-TNEF-Correlator: Thread-Topic: Problem with the classloader in jakarta-tomcat-5.0.28 - cannot add a jar file to class repository Thread-Index: AcVGTDgaQOh5BfPITDCSQNNgbypw+gAGC2YQABtO6NA= From: "Akoulov, Alexandre [IT]" To: "Tomcat Users List" X-OriginalArrivalTime: 22 Apr 2005 00:48:19.0684 (UTC) FILETIME=[FA556A40:01C546D4] X-Scanned-By: MIMEDefang 2.48 on 169.186.247.39 X-Virus-Checked: Checked X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N ------_=_NextPart_001_01C546D4.FA17F8D6 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable Thanks Chuck for your reply. I still think it is a bug!!!=20 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:Chuck.Caldarale@unisys.com] 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:alexandre.akoulov@citigroup.com] > Subject: Problem with the classloader in=20 > jakarta-tomcat-5.0.28 - cannot add a jar file to class repository >=20 > ClassLoaderFactory#createClassLoader(File unpacked[], File=20 > packed[], URL urls[], ClassLoader parent) is the actual=20 > method that creates class loaders. The very first argument to=20 > this method contains jar files or directories ( that is where=20 > the name "unpacked" comes from ).=20 >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: tomcat-user-unsubscribe@jakarta.apache.org For additional commands, e-mail: tomcat-user-help@jakarta.apache.org -----Original Message----- From: Akoulov, Alexandre [IT]=20 Sent: Thursday, 21 April 2005 6:29 PM To: tomcat-user@jakarta.apache.org 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. =09 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 -------------------------------------------------------------------------= ---- =09 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 ).=20 =09 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 !=3D null) { for (int i =3D 0; i < unpacked.length; i++) { File file =3D unpacked[i]; if (!file.exists() || !file.canRead()) continue; if (debug >=3D 1) log(" Including directory or JAR "=20 + file.getAbsolutePath()); URL url =3D new URL("file", null, file.getCanonicalPath() + = File.separator); list.add(url.toString()); } } -------------------------------------------------------------------------= ---- =20 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. =09 After ClassLoaderFactory#createClassLoader adds all repositories to its = repository list it converts this list to array and constructs = StandardClassLoader with it: =09 -------------------------------------------------------------------------= ---- String array[] =3D (String[]) list.toArray(new String[list.size()]); StandardClassLoader classLoader =3D null; if (parent =3D=3D null) classLoader =3D new StandardClassLoader(array); -------------------------------------------------------------------------= ---- =20 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] =3D new URL(null, input[i], streamHandler); ..... } -------------------------------------------------------------------------= ---- =20 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 ). =20 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[] ). =20 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. =20 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. =20 =20 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. =20 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =20 Proposed solution =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= 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: =20 -------------------------------------------------------------------------= ---- if (unpacked !=3D null) { for (int i =3D 0; i < unpacked.length; i++) { File file =3D unpacked[i]; if (!file.exists() || !file.canRead()) continue; if (debug >=3D 1) log(" Including directory or JAR "=20 + file.getAbsolutePath()); =20 // THE FIX StringBuffer filePath =3D new = StringBuffer(file.getCanonicalPath()); if ( file.isDirectory() ) {=20 // Only add a file separator if a file represents a = directory filePath.append(File.separator); } =20 URL url =3D new URL("file", null, filePath.toString()); list.add(url.toString()); } }=09 -------------------------------------------------------------------------= ---- =09 =09 Kind regards, Alex. =09 --------------------------------------------------------------------- To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org For additional commands, e-mail: tomcat-user-help@jakarta.apache.org ------_=_NextPart_001_01C546D4.FA17F8D6 Content-Type: text/plain; charset=us-ascii --------------------------------------------------------------------- To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org For additional commands, e-mail: tomcat-user-help@jakarta.apache.org ------_=_NextPart_001_01C546D4.FA17F8D6--