Solving the "JAR hell" issue with different 3rd party JAR files

891 views
Skip to first unread message

Fred Roeber

unread,
Jan 12, 2010, 8:34:34 AM1/12/10
to javaloader-dev
We were having a problem that it seems many others have been having
where our code throws various exceptions when loaded with JavaLoader
under ColdFusion that didn't happen when the application is run
standalone. This problem is similar to the one in "Integrating iBatis
Framework " and "Can someone help me understand what is going on here
please?" and even "Log4j + JavaLoader and -Dlog4j.ignoreTCL=true".
After almost a week banging my head against walls trying to research
this I have finally figured out a solution that works.

Our application is using JavaLoader 0.6. It also uses a whole lot of
3rd party libraries including:
activation-1.1.1.jar
commons-logging-1.1.1.jar
freemarker-2.3.15.jar
ibatis-2.3.4.726.jar
jaxen-1.1.1.jar
jdom-1.1.jar
jdom-jaxen-1.0-r1.jar
joda-time-1.6.jar
jtds-1.2.2.jar
log4j-1.2.15.jar
mail-1.4.1.jar
msbase.jar
mssqlserver.jar
msutil.jar
resolver-2.9.1.jar
serializer-2.9.1.jar
xalan-2.7.1.jar
xercesImpl-2.9.1.jar
xml-apis-2.9.1.jar

I include the list to show that it includes a number of different
packages that can cause problems in JavaLoader unless you do something
along the lines of the fixes I outline later. Things like Log4j, JDOM,
XALAN, iBatis, jtds.

As background, before I figured out how to fix this "right", our
"solution" to the problem was to just stick all of our library JARs in
the ColdFusion lib directory where some of them overrode older
versions that came with ColdFusion. While this sort of worked (as far
as we could tell), it was such a bad solution since it could cause
ColdFusion to break in strange ways if any of the newer libraries
weren't perfectly backward compatible with the older ColdFusion
versions. Also, unless you went into ColdFusion admin and changed the
ColdFusion class path or deleted specific ColdFusion 3rd party JARs,
you wouldn't even be using your newer packages because the ColdFusion
class path includes each lib JAR by name before it includes the
library directory.

What we really wanted to do was load all these libraries using
JavaLoader from a separate directory that ColdFusion didn't know about
(I posted the code we used to do this to under the "Problem when
loading multiple times" topic yesterday). When we did this and ran
things there would be problems like iBatis not being able to read
config files, XML parsing failing with incompatible SAXParser
exceptions and Log4j not working due to different appenders not being
consistent. The details aren't that important since all the problems
went away by simply making sure that the objects loaded with
JavaLoader were run with the right "thread context class
loader" (which I'll call the TCCL below).

I went through lots of web sites trying to figure out the problems I
was having. It became clear they were all due to class loader issues.
I found two discussions that were particularly helpful in
understanding the issues. They aren't simple to follow unless you have
some background in Java class loading. However, they are helpful to
finding a solution:

http://articles.qos.ch/classloader.html
http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html

One thing that is important for this issue is to understand that
JavaLoader uses a "child first" loader approach instead of the more
standard "delegation" or "parent first" loader approach. It works this
way because Mark took some Apache URLClassLoader code supporting
"parent first" loading and tweaked it to instead be "child first".
This code is NetworkClassLoader.java class that is in the lib/cl.jar
file that is part of the JavaLoader 0.6 distribution.

We really do want a "child first" loader since that is what allows an
application using JavaLoader to supply a different version than
ColdFusion uses of packages that it needs/wants to use. Child first is
the way many web application servers work.

So, the root of the problem is that many third party packages have
code that uses the class loader associated with the thread the package
is running in (the TCCL) and not the class's class loader (i.e. the
one that loaded the package). In normal ColdFusion, when a cfobject is
invoked, the TCCL is set to the ColdFusion class loader and not the
JavaLoader that loaded the package. If the library tries to assign/
cast some object created during loading to one it creates dynamically
using the TCCL, you get an exception since the loaders are different
and the objects are therefor incompatible. To fix this, you just need
to make sure that the TCCL is set to the JavaLoader that loaded the
code rather than the ColdFusion one. Once this is done, all the code
(at least that we have used) just magically works.

I'm going to show the code we used to set the TCCL. The solution we
used isn't particularly elegant because it requires that some code be
run at the entry to and exit from every method that can be invoked
from ColdFusion. The entry code changes the TCCL to the JavaLoader
that loaded the class and the exit code restores the original TCCL.
And it's real important that the exit code always run so that
ColdFusion doesn't break after return from the method. Also, it's
important that the entry and exit code be used before running any
static initialization code in your application that calls the third
party JARs. It wasn't hard for us to add this code to our application
because there is only one class with all the API functions and we had
already carefully set up the static initialization code to capture any
initialization exceptions and save them so they could be reported on
later method invocations. However, it would be nice if there was some
way to more automatically or centrally set/restore the TCCL.

The actual code you need to run is pretty simple:

public class OurApp {

/*********************************************************
* Constants
*/

/** Capture the class loader used to load this class. It's the one
* in control of loading the application.
*/
private static final ClassLoader CLASS_LOADER;

/** Store any exception detected during static initialization */
private static final Throwable INIT_EXCEPTION;

/** A logger handle */
private static final Logger LOGGER;

/*********************************************************
* Handle any constants needing initialization.
*/
static
{
Throwable initException = null;
Logger logger = null;

/* Set up the right "class context loader" for this code */
CLASS_LOADER = DirectedCoaching.class.getClassLoader();
ClassLoader oldLoader = enter();

try {
/* Initialize the logger */
logger = Logger.getLogger("dc");
} catch (Throwable e) {
/* Store any exception detected for later reporting */
initException = e;
} finally {
/* Always make sure constants have a value */
INIT_EXCEPTION = initException;
LOGGER = logger;

/* Restore the original loader */
exit(oldLoader);
}
}

/**
* This method and the exit method that follows provide a critical
* service needed to run the application JAR code in a "server"
* environment (for instance under ColdFusion JRun). This enter
method
* MUST be called before doing any other actions (even executing
the
* static initializer block). The exit method must ALWAYS be
called
* before exiting a method that called this enter one. This may
require
* using a "finally" exception block to make sure calls aren't
missed.
*
* This method takes care of setting the thread's "context class
* loader" to the ClassLoader that loaded this page. This solves
* problems reported in SIR 1250 and 1168 (among others).
*
* Some key discussions of the issues associated with this code
are
* available from the links:
*
* http://articles.qos.ch/classloader.html
* http://www.javaworld.com/javaworld/javaqa/2003-06/01-qa-0606-load.html
*
* @return the original Thread context loader so it can be
restored.
*/
private static ClassLoader enter()
{
Thread myThread = Thread.currentThread();
ClassLoader oldLoader = myThread.getContextClassLoader();

myThread.setContextClassLoader(CLASS_LOADER);
return oldLoader;
}

/**
* We are exiting the API so restore the original class loader for
the
* thread.
*
* @param loader The original Thread context loader to be
restored.
*/
private static void exit(ClassLoader loader)
{
Thread.currentThread().setContextClassLoader(loader);
}

==================

The calls to enter() and exit() that are shown in the static
initializer code above need to be put into any method invoked from
ColdFusion that directly or indirectly uses code that needs a properly
set TCCL. But if that is done then the code all works.

I want to wrap up with one last thing. As part of researching this I
looked pretty closely at the class loading being done by JavaLoader.
Specifically as done by NetworkClassLoader.java. As I stated above,
Mark updated the original parent first URLClassLoader from Apache to
get the desired new operation. He followed a reasonable strategy of
"make minimal changes to others code". However, since the loader is a
core component of getting JavaLoader to work right and because the
change from parent first to child first is really quite significant, I
think a more substantial rewrite of the code is warranted. I've
attached an updated version of the loader code that I went through to
streamline operation and correct comments. Also, because the loader
now always checks the things it can load before delegating loading of
something to the parent, there is one optimization I added that
significantly improves operation. I added code that tracks resources
that have already been attempted to be loaded and not found. There is
no reason to try to look for those resources again when they are
requested again. I also changed the commented out debug code to use
log4j which allows the loading debug messages to show up directly in
the ColdFusion output log.

So the updated code is below and that's all I have to say about this
issue. As always, I want to thank Mark for the excellent work he did
providing all this JavaLoader code. In our case it solves a great need
and, now that we understand how to use it, works great!

/*
*
====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software
itself,
* if and wherever such third-party acknowlegements normally
appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products
derived
* from this software without prior written permission. For
written
* permission, please contact apa...@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
====================================================================
*/

package com.compoundtheory.classloader;

import java.net.*;
import java.util.*;
import java.io.*;
//import org.apache.log4j.Logger;

/**
* The correct name for this class should be URLClassLoader.
* But there is already a class by that name in JDK1.2.
*
* I have had quite a few problems with URLClassLoader in
* past, so I ended up writing this ClassLoader. I found that
* the Java 2's URLClassLoader, does not close the Jar file once
* opened. It is a pretty good optimization step, but if you
* modify the class in the jar file, it does not pick it up. Some
* operating systems may not let you modify the jar file while it is
* still open. IMHO, it does make sense to close the jar file
* after you are done reading the class data. But this approach may
not
* get you the performance of the URLClassLoader, but it works in all
* cases and also runs on JDK1.1. I have enhanced this class loader
* to read all the zip/jar entries once & cache the data, so that
* there is no overhead of opening/closing jar file to pick up
* each entry.
*
* Modified slightly by Mark Mandel to work specifically with
* ColdFusion, in specific contexts.
*
* @author Harish Prabandham
*/
public class NetworkClassLoader extends ClassLoader {
private ClassLoader parent = null; // parent classloader
private Hashtable classCache = new Hashtable();
private Set unfoundResources = new HashSet();
private Hashtable urlset = new Hashtable();

/* Set up a logger to use for debug messages. */
//private static final Logger LOGGER = Logger.getLogger
("NetClassLoad");

public NetworkClassLoader() {
super(null);
//debug("creating network class loader...");
}

/**
* Creates a new instance of the class loader.
* @param delegate/parent class loader.
*/
public NetworkClassLoader(ClassLoader parent) {
super(parent);
//debug("creating network class loader... with a parent");
setParent(parent);
}

/**
* Sets the parent/delegate class loader.
* @param delegate/parent class loader.
*/
protected final void setParent(ClassLoader parent) {
this.parent = parent;
}

/**
* Adds the given URL to this class loader. If the URL
* ends with "/", then it is assumed to be a directory
* otherwise, it is assumed to be a zip/jar file. If the
* same URL is added again, the URL is re-opened and this
* zip/jar file is used for serving any future class requests.
* @param URL where to look for the classes.
*/
public synchronized void addURL(URL url) {
//debug("Adding url: " + url);
if(!urlset.containsKey(url)) {
try {
urlset.put(url, new URLResourceReader(url));
}catch(IOException ioe){
// Probably a bad url...
}
} else {
// remove the old one & add a new one...
try{
//debug("Replace old url");
URLResourceReader newu = new URLResourceReader(url);
URLResourceReader oldu = (URLResourceReader) urlset.get
(url);
oldu.close();
urlset.remove(url);
urlset.put(url, newu);
} catch (IOException ioe) {
}
}
// May get new resources from new URL so have to forget what
has not
// been found
unfoundResources.clear();
}

/**
* @return An enumeration of URLs where this class loader
* looks for classes.
*/
public Enumeration getURLs() {
return urlset.keys();
}

/**
* Call this to bypass the implementation of loadClass.
*/
public Class findClass(String name) throws ClassNotFoundException
{
byte[] b = loadClassData(name);
if (b != null) {
//debug("findClass found " + name);
return defineClass(name, b, 0, b.length);
} else {
//debug("findClass didn't find " + name);
throw new ClassNotFoundException(name);
}
}

protected byte[] loadResource(URL url, String resourceName)
throws IOException {
URLResourceReader urr = (URLResourceReader) urlset.get(url);
//debug("Trying to load from " + urr + " " + resourceName);
if(urr != null) {
return urr.getResource(resourceName);
}
return null;
}

protected byte[] loadResource(String resource) {
byte[] barray = null;

// Don't bother searching if we know it's not there
if (unfoundResources.contains(resource)) {
return null;
}

for(Enumeration e = urlset.keys(); e.hasMoreElements();) {
URL url = (URL) e.nextElement();

try {
barray = loadResource(url, resource);
} catch(Exception ex) {
} finally {
if(barray != null)
break;
}
}
// Remember resources we couldn't find
if (barray == null) {
unfoundResources.add(resource);
}
return barray;
}

protected byte[] loadClassData(String classname) {
String resourceName = classname.replace('.', '/') + ".class";
return loadResource(resourceName);
}

/**
* Overridden to search for a resource and return
* a "jar"-style URL or normal "file" URL as necessary.
*/
protected URL findResource(String name) {
//debug( "findResource: " + name );
URL url;
byte[] barray = null;

// Don't bother searching if we know it's not there
if (unfoundResources.contains(name)) {
return null;
}

for (Enumeration e = urlset.keys(); e.hasMoreElements(); ) {
url = (URL) e.nextElement();
try {
barray = loadResource(url, name); // loads fully:
wasteful
} catch(Exception ex) {
// do nothing
}
if (barray != null) {
try {
String ref = url.toString();
if (ref.endsWith(".jar")) {
//debug("jar:" + ref + "!/" + name);
return new URL("jar:" + ref + "!/" + name);
} else {
//debug(new URL(url, name).toString());
return new URL(url, name);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}
// Remember resources we couldn't find
unfoundResources.add(name);
return null;
}

/**
* @return The resource as the input stream if such a resource
* exists, otherwise returns null.
*/
public InputStream getResourceAsStream(String name) {
//debug("getResourceAsStream: " + name);
InputStream istream = null;

// Algorithm:
//
// 1. first attempt to get the resource from the url set.
// 2. next check the delegate/parent class loader for the
resource
// 3. then check the system path for the resource
//

// Lets load it ourselves.
byte[] data = loadResource(name);
if(data != null) {
return new ByteArrayInputStream(data);
}

// Lets check the parent/delegate class loader for the
resource.
if(parent != null) {
istream = parent.getResourceAsStream(name);
if(istream != null)
return istream;
}

// The system path is the last place to find the resource.
return getSystemResourceAsStream(name);
}

public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class c;

// Algorithm:
//
// 1. check the class cache
// 2. next then attempt to load classes from the URL set.
// 3. next check the delegate/parent class loader.
// 4. next check the system class loader.
//
// Note- the order of checking results in this class loader
overriding
// the parent and system class loader

// Lets see if the class is in the cache..

//debug("load class:: " + name + " resolve: " + resolve);
//debug(classCache.toString());

c = (Class) classCache.get(name);

if(c == null) {
// Lets see if we find the class all by ourselves.
byte[] data = loadClassData(name);

if(data != null) {
// found class data so define it and place in cache
//debug("found data, attempting to define " + name);
c = defineClass(name, data, 0, data.length);
//debug("placing " + name + " in cache");
classCache.put(name, c);
}
}

// Lets see if the class is in parent class loader if there is
one
// or the system class loader if there isn't.
if (c == null) {
if(parent != null) {
//debug("check parent class loader for " + name);
c = parent.loadClass(name);
if (c == null)
throw new ClassNotFoundException(name);
} else {
//debug("check system class loader for " + name);
c = findSystemClass(name);
}
}

//debug("found class " + name);
if(resolve) {
resolveClass(c);
}
return c;
}

/**
* This method resets this ClassLoader's state. It completely
* removes all the URLs and classes in this class loader cache.
*/
public final void clear() {
classCache.clear();
unfoundResources.clear();
urlset.clear();
}

/**
* This method resets this ClassLoader's state and resets the
* references for garbage collection.
*/
protected void finalize() throws Throwable {
// Cleanup real well. Otherwise, this can be
// a major source of memory leaks...

// remove all the urls & class entries.
clear();

parent = null;
classCache = null;
unfoundResources = null;
urlset = null;
}


/*
private void debug(String str)
{
LOGGER.info(str);
}
*/
}

Jaime Metcher

unread,
Jan 13, 2010, 6:40:52 PM1/13/10
to javaloa...@googlegroups.com
Fred,
 
Ingenious.  I'm curious as to how this would affect any framework that's in the habit of using the TCCL that has been loaded by the servlet before CF and then JavaLoader get control.  In effect, you've just switched its classloader on it.  I would guess a rash of type compatibility errors would ensue.  With a bit of luck none of the libraries used by CF fall into this category, and you can probably avoid loading anything at this level yourself.
 
Jaime

Mark Mandel

unread,
Jan 13, 2010, 8:21:52 PM1/13/10
to javaloa...@googlegroups.com
A couple of thoughts on this -

On Wed, Jan 13, 2010 at 12:34 AM, Fred Roeber <fro...@cox.net> wrote:
I'm going to show the code we used to set the TCCL. The solution we
used isn't particularly elegant because it requires that some code be
run at the entry to and exit from every method that can be invoked
from ColdFusion. The entry code changes the TCCL to the JavaLoader
that loaded the class and the exit code restores the original TCCL.
And it's real important that the exit code always run so that
ColdFusion doesn't break after return from the method. Also, it's
important that the entry and exit code be used before running any
static initialization code in your application that calls the third
party JARs. It wasn't hard for us to add this code to our application
because there is only one class with all the API functions and we had
already carefully set up the static initialization code to capture any
initialization exceptions and save them so they could be reported on
later method invocations. However, it would be nice if there was some
way to more automatically or centrally set/restore the TCCL.


Depending on the library, switching the ThreadContextClassLoader is a really good way to go. I've done that myself when loading up libraries such as Hibernate under ColdFusion 9.

A lot of libraries that access the TCCL do give you a method to allow you to tell it which classloader to use when it attempts to load stuff via a classloader.  A class example of this is Spring, which allows you to specify which classloader to use, which means you don't have to do the sort of classloader juggeling you would otherwise.  That being said, libraries like dom4j don't, and you have to juggle the TCCL, just like you said.

That being said, I'm surprised you have to wrap every method with a switchover of the TCCL. In my experience, I've only ever really needed to do it when first initialising a library (like Spring, Hibernate etc), as the TCCL tends to be used to to find/create singletons.  Once the library has been loaded, I've not seen an instance where I've needed to juggle it back and forth.

(For interest sake - it's interesting to know that createObject() uses the TCCL to load up classes, so you can have some fun there too... but I digress).


I want to wrap up with one last thing. As part of researching this I
looked pretty closely at the class loading being done by JavaLoader.
Specifically as done by NetworkClassLoader.java. As I stated above,
Mark updated the original parent first URLClassLoader from Apache to
get the desired new operation. He followed a reasonable strategy of
"make minimal changes to others code". However, since the loader is a
core component of getting JavaLoader to work right and because the
change from parent first to child first is really quite significant, I
think a more substantial rewrite of the code is warranted. I've
attached an updated version of the loader code that I went through to
streamline operation and correct comments. Also, because the loader
now always checks the things it can load before delegating loading of
something to the parent, there is one optimization I added that
significantly improves operation. I added code that tracks resources
that have already been attempted to be loaded and not found. There is
no reason to try to look for those resources again when they are
requested again. I also changed the commented out debug code to use
log4j which allows the loading debug messages to show up directly in
the ColdFusion output log.

I had a quick glance through it (I probably should have done a better job of going through it, I admit ;o) ), the basic gist of what you've done is such that - you record if the child classloader can't find a Class, and therefore passes the delegation up to the Parent?

Given that 99% of what most people do, myself included, this has probably never come up as a performance concern.  That being said, given the scenario that you outlined previously, where you have multiple tiered classloaders, this make perfect sense.  I will do a review of the code you have written, and incorate it into the NetworkClassLoader, it sounds like a very good idea, so thanks for that!

Mark


--
E: mark....@gmail.com
T: http://www.twitter.com/neurotic
W: www.compoundtheory.com

Fred Roeber

unread,
Jan 13, 2010, 10:03:47 PM1/13/10
to javaloader-dev

On Jan 13, 8:21 pm, Mark Mandel <mark.man...@gmail.com> wrote:

> Depending on the library, switching the ThreadContextClassLoader is a really
> good way to go. I've done that myself when loading up libraries such as
> Hibernate under ColdFusion 9.
>
> A lot of libraries that access the TCCL do give you a method to allow you to
> tell it which classloader to use when it attempts to load stuff via a
> classloader.  A class example of this is Spring, which allows you to specify
> which classloader to use, which means you don't have to do the sort of
> classloader juggeling you would otherwise.  That being said, libraries like
> dom4j don't, and you have to juggle the TCCL, just like you said.
>
> That being said, I'm surprised you have to wrap every method with a
> switchover of the TCCL. In my experience, I've only ever really needed to do
> it when first initialising a library (like Spring, Hibernate etc), as the
> TCCL tends to be used to to find/create singletons.  Once the library has
> been loaded, I've not seen an instance where I've needed to juggle it back
> and forth.

Mark, You are right on several fronts. As you say, some packages let
you pick the classloader to use. For instance, there was an iBatis fix
mentioned in another discussion thread that did that. We had found and
applied that fix too for our iBatis code. Changing the TCCL at the
outset avoids the need to use those specific fixes and I think is a
more general/easy fix.

I also suspect you are right on the fact that you only have to wrap
the initialization code for the different packages you use. However,
due to Java lazy loading I believe you don't really know when the 3rd
party library initialization code will get run. It won't run until you
happen to reference the first object that uses that library. Therefor
I think it's just safest to wrap all the method calls. I do wish there
was some easier/tricky method where you could put this into the CF
invoke method or something.

I did see an Adobe bug fix report that talked about them making
changes to not mess with the TCCL in some cases that they used to
because it was causing some user's problems. They decided to leave it
in the user's hands what they wanted to do. As one good writeup I saw
said "Although Java resource loading remains an esoteric topic, J2SE
relies on various load strategies more and more with every major
platform upgrade. Java will be in serious trouble if this area is not
given some significantly better design considerations." I certainly
agree with that opinion. There doesn't seem to be any universal choice
of how to always set the TCCL. However, I've found that for the
packages we use the TCCL change I explained above solved the problem.
As people often say with this stuff YMMV.
Fred

Mark Mandel

unread,
Jan 13, 2010, 10:07:54 PM1/13/10
to javaloa...@googlegroups.com

However, I've found that for the
packages we use the TCCL change I explained above solved the problem.
As people often say with this stuff YMMV.
Fred

Yup, totally fair enough - and a good topic to be discussed for CF-Java integration to be sure!

Mark Mandel

unread,
Jan 14, 2010, 6:05:43 PM1/14/10
to javaloa...@googlegroups.com
Oh, I forgot to ask -

The changes you made to NetworkClassLoader - was that the 1.0 version, or the 0.6 version?

Mark
Hands-on ColdFusion ORM Training @ cf.Objective() 2010
www.ColdFusionOrmTraining.com/

Fred

unread,
Jan 15, 2010, 6:52:44 PM1/15/10
to Mark Mandel, javaloa...@googlegroups.com
Mark Mandel wrote:
> Oh, I forgot to ask -
>
> The changes you made to NetworkClassLoader - was that the 1.0 version,
> or the 0.6 version?

The 0.6 version. I didn't upgrade to 1.0 because I didn't (yet) need the
extra dynamic load features and wanted to hunt my problems against a
smaller sized code base. Did you change NetworkClassLoader.java for 1.0?
I guess I sort of thought that wouldn't be needed.
Fred

Mark Mandel

unread,
Jan 15, 2010, 8:40:59 PM1/15/10
to javaloa...@googlegroups.com
There are some additions to the ClassLoader in 1.0 that were needed to make to enable Spring compatability.
 
That being said, I can take the ideas you have presented and extend them into the new features. Easy enough, just wanted to be sure.
 
Mark

Mark Mandel

unread,
Jan 18, 2010, 1:50:25 AM1/18/10
to javaloa...@googlegroups.com
Fred, I just incorporated your changes into the NetworkClassLoader - if you can, have a look, did I miss anything?

http://svn.riaforge.org/javaloader/trunk/networkClassLoader/src/com/compoundtheory/classloader/NetworkClassLoader.java

I'll release this as 1.0 Beta 2, just so that people have a chance to play with it before I push it to a Stable release.

Mark
Message has been deleted

Fred Roeber

unread,
Feb 15, 2010, 5:15:51 PM2/15/10
to javaloa...@googlegroups.com
Phil wrote:
> Fred,
>
> Thank you for your post on how to solve this vexing problem. In
> implementing your solution I have a question. When you get the
> previous class loader you code:
>
> CLASS_LOADER = DirectedCoaching.class.getClassLoader();
>
> What is the DirectedCoaching class? Some quesses: a class within a
> ColdFusion jar; a class of your own loaded through a call to CF's
> createObject; a random class in your application that has not been
> loaded and so it's loader is the current thread's loader.

>
> On Jan 12, 7:34 am, Fred Roeber <froe...@cox.net> wrote:
>
>> We were having a problem that it seems many others have been having
>> where our code throws various exceptions when loaded with JavaLoader
>> under ColdFusion that didn't happen when the application is run
>> standalone.
>> ...
>>

Sorry Phil. My bad. That was a simple "cut and paste error". I took our
"real" code and attempted to sanitize it. That DirectedCoaching should
just be OurApp (i.e. the class that the code is being run from).

--

| Fred J Roeber
| fro...@cox.net


Reply all
Reply to author
Forward
0 new messages