Re: controlling ClassLoader when programmatically invoking Ant

2012-07-22 Thread Vimil Saju
So this time I actually did this. I created this parentless ClassLoader and
created a Project object from it. And what happened? The moment I tried to
assign this object to a Project variable, I got a ClassCastException:
org.apache.tools.ant.Project cannot be cast to
org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.


I think to prevent class-cast issue, you should first create a class with just 
a static main method, then use the parentless class loader to create an 
instance of this class and invoke its main method through reflection.
 All the ant related code should be then written in then main method of the 
class that you created.

The reason you are getting the class-cast exception is because you are creating 
the Project object using say classloaderA and then trying to access that object 
from a class that was loaded from another classloader. 



 From: Mitch Gitman mgit...@gmail.com
To: Ant Developers List dev@ant.apache.org 
Sent: Saturday, July 21, 2012 6:16 PM
Subject: Re: controlling ClassLoader when programmatically invoking Ant
 
Quick update for anyone who's curious.

I'd forgotten that I'd asked much the same question on the ant-user list
back on May 31. This was back when the contamination of the child classpath
with the parent classpath was literally causing the tests to fail. And same
as with this thread, Nicolas L. was kind enough to respond. See thread,
example of correctly consuming an Ant project programmatically.

What's funny (and sad in a way) is that today I went down much the same
path I had laid in the earlier thread without even recollecting that
thread. Here's what I wrote earlier:
***
The one way I may have to tweak this ... is to do:
new URLClassLoader(jars, null);

Passing null for the extra ClassLoader argument obviates the possibility of
the parent classloader creeping in.
***
So this time I actually did this. I created this parentless ClassLoader and
created a Project object from it. And what happened? The moment I tried to
assign this object to a Project variable, I got a ClassCastException:
org.apache.tools.ant.Project cannot be cast to
org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.

I also tried just calling Project.setCoreLoader() with this URLClassLoader,
but that didn't change the way the Ivy JAR and such were being loaded.

At this point, I can think of a few ways to address this problem:
1. Create a parent ClassLoader just for all the Ant libraries and put JUnit
itself and the entire test classpath in a child classloader.
2. Run the Launcher class with the sandboxed ClassLoader and have a build
listener and build logger write the messages and out/err to the filesystem.
Then to do the assertions, read the files after the fact.
3. Obtain an Object instance rather than a Project instance and use
reflection to call the few methods I have to call on it.

#1 scares me! #2 is defeating much of the purpose of doing all this
programmatically. #3 ain't pretty, but so far it seems doable.

On Sat, Jul 21, 2012 at 9:33 AM, Mitch Gitman mgit...@gmail.com wrote:

 Nicolas, thanks. I was one class off. I was looking at Main and AntMain
 when I should have been looking at Launcher. Seeing the type names and the
 main method threw me off. And this corroborates my brief follow-up that I
 could be doing something with URLClassLoader. Better for me to try to
 leverage Launcher though than reinvent that wheel.

 Let me see how far I get with that.

 I do have to take issue with the one point you make: But If I were you, I
 wouldn't bother trying to mimic Ant classloading in a unit test. The
 important thing is to be sure that you run against the expected version of
 Ant and Ivy.

 First, this is not a unit test. It's an integration test or a functional
 test, and if it doesn't emulate the real-life behavior in the wild, then
 what use is it?

 Even if we are treating this as a unit test, you can't really say that
 inadvertently picking up everything in the parent ClassLoader is the
 equivalent of mocking or stubbing services and components as one normally
 does when creating pure unit tests. Consider that there could be a ton of
 classes in the IDE's ClassLoader that have nothing whatsoever to do with
 the Ant Project being executed.

 And this brings me to my last concern. I have already encountered a
 problem where some static functionality in some superfluous classes in the
 IDE-inherited ClassLoader was causing the JUnit-invoked Project build to
 fail.

 Even so, to my mind, the uncontrolled success I'm seeing now is no less
 troubling than the uncontrolled failure I was seeing then. If you're a
 biologist conducting an experiment, you don't want to find out your
 cultures were growing only because the Petri dish got contaminated.

 On Sat, Jul 21, 2012 at 6:10 AM, Nicolas Lalevée 
 nicolas.lale...@hibnet.org wrote:

 Hi Mitch,

 Le 21 juil. 2012 à 07:37, Mitch Gitman a écrit :

  Technically

Re: controlling ClassLoader when programmatically invoking Ant

2012-07-22 Thread Mitch Gitman
Right, what you describe falls under the #1 option I'd mentioned:
1. Create a parent ClassLoader just for all the Ant libraries and put
JUnit itself and the entire test classpath in a child classloader.

Considering that the code in question consists of JUnit tests that I WANT
to run from within an IDE and that I NEED to run from Ant, together with
producing the customary reports, this could get complicated pretty fast.

Right now, I'm pursuing my option #3, the complications for which are:
* Creating a URLClassLoader that uses a scaled-down analog to the Launcher
URLClassLoader.
* Deploying a JAR containing nothing but the custom BuildListener and
BuildLogger to Ant lib.
* Accessing the Project and custom BuildListener and BuildLogger using
strictly reflection in the Ant test runner code.

On Sun, Jul 22, 2012 at 5:27 AM, Vimil Saju vimils...@yahoo.com wrote:

 So this time I actually did this. I created this parentless ClassLoader
 and
 created a Project object from it. And what happened? The moment I tried to
 assign this object to a Project variable, I got a ClassCastException:
 org.apache.tools.ant.Project cannot be cast to
 org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.


 I think to prevent class-cast issue, you should first create a class with
 just a static main method, then use the parentless class loader to create
 an instance of this class and invoke its main method through reflection.
  All the ant related code should be then written in then main method of
 the class that you created.

 The reason you are getting the class-cast exception is because you are
 creating the Project object using say classloaderA and then trying to
 access that object from a class that was loaded from another classloader.


 
  From: Mitch Gitman mgit...@gmail.com
 To: Ant Developers List dev@ant.apache.org
 Sent: Saturday, July 21, 2012 6:16 PM
 Subject: Re: controlling ClassLoader when programmatically invoking Ant

 Quick update for anyone who's curious.

 I'd forgotten that I'd asked much the same question on the ant-user list
 back on May 31. This was back when the contamination of the child classpath
 with the parent classpath was literally causing the tests to fail. And same
 as with this thread, Nicolas L. was kind enough to respond. See thread,
 example of correctly consuming an Ant project programmatically.

 What's funny (and sad in a way) is that today I went down much the same
 path I had laid in the earlier thread without even recollecting that
 thread. Here's what I wrote earlier:
 ***
 The one way I may have to tweak this ... is to do:
 new URLClassLoader(jars, null);

 Passing null for the extra ClassLoader argument obviates the possibility of
 the parent classloader creeping in.
 ***
 So this time I actually did this. I created this parentless ClassLoader and
 created a Project object from it. And what happened? The moment I tried to
 assign this object to a Project variable, I got a ClassCastException:
 org.apache.tools.ant.Project cannot be cast to
 org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.

 I also tried just calling Project.setCoreLoader() with this URLClassLoader,
 but that didn't change the way the Ivy JAR and such were being loaded.

 At this point, I can think of a few ways to address this problem:
 1. Create a parent ClassLoader just for all the Ant libraries and put JUnit
 itself and the entire test classpath in a child classloader.
 2. Run the Launcher class with the sandboxed ClassLoader and have a build
 listener and build logger write the messages and out/err to the filesystem.
 Then to do the assertions, read the files after the fact.
 3. Obtain an Object instance rather than a Project instance and use
 reflection to call the few methods I have to call on it.

 #1 scares me! #2 is defeating much of the purpose of doing all this
 programmatically. #3 ain't pretty, but so far it seems doable.




Re: controlling ClassLoader when programmatically invoking Ant

2012-07-22 Thread Vimil Saju
I'll probably have to see some code to understand what's going on, but 
reflection will prevent classcast exceptions when accessing methods of a class 
loaded from a different class loader. 



 From: Mitch Gitman mgit...@gmail.com
To: Ant Developers List dev@ant.apache.org 
Sent: Sunday, July 22, 2012 8:52 AM
Subject: Re: controlling ClassLoader when programmatically invoking Ant
 
Right, what you describe falls under the #1 option I'd mentioned:
1. Create a parent ClassLoader just for all the Ant libraries and put
JUnit itself and the entire test classpath in a child classloader.

Considering that the code in question consists of JUnit tests that I WANT
to run from within an IDE and that I NEED to run from Ant, together with
producing the customary reports, this could get complicated pretty fast.

Right now, I'm pursuing my option #3, the complications for which are:
* Creating a URLClassLoader that uses a scaled-down analog to the Launcher
URLClassLoader.
* Deploying a JAR containing nothing but the custom BuildListener and
BuildLogger to Ant lib.
* Accessing the Project and custom BuildListener and BuildLogger using
strictly reflection in the Ant test runner code.

On Sun, Jul 22, 2012 at 5:27 AM, Vimil Saju vimils...@yahoo.com wrote:

 So this time I actually did this. I created this parentless ClassLoader
 and
 created a Project object from it. And what happened? The moment I tried to
 assign this object to a Project variable, I got a ClassCastException:
 org.apache.tools.ant.Project cannot be cast to
 org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.


 I think to prevent class-cast issue, you should first create a class with
 just a static main method, then use the parentless class loader to create
 an instance of this class and invoke its main method through reflection.
  All the ant related code should be then written in then main method of
 the class that you created.

 The reason you are getting the class-cast exception is because you are
 creating the Project object using say classloaderA and then trying to
 access that object from a class that was loaded from another classloader.


 
  From: Mitch Gitman mgit...@gmail.com
 To: Ant Developers List dev@ant.apache.org
 Sent: Saturday, July 21, 2012 6:16 PM
 Subject: Re: controlling ClassLoader when programmatically invoking Ant

 Quick update for anyone who's curious.

 I'd forgotten that I'd asked much the same question on the ant-user list
 back on May 31. This was back when the contamination of the child classpath
 with the parent classpath was literally causing the tests to fail. And same
 as with this thread, Nicolas L. was kind enough to respond. See thread,
 example of correctly consuming an Ant project programmatically.

 What's funny (and sad in a way) is that today I went down much the same
 path I had laid in the earlier thread without even recollecting that
 thread. Here's what I wrote earlier:
 ***
 The one way I may have to tweak this ... is to do:
 new URLClassLoader(jars, null);

 Passing null for the extra ClassLoader argument obviates the possibility of
 the parent classloader creeping in.
 ***
 So this time I actually did this. I created this parentless ClassLoader and
 created a Project object from it. And what happened? The moment I tried to
 assign this object to a Project variable, I got a ClassCastException:
 org.apache.tools.ant.Project cannot be cast to
 org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.

 I also tried just calling Project.setCoreLoader() with this URLClassLoader,
 but that didn't change the way the Ivy JAR and such were being loaded.

 At this point, I can think of a few ways to address this problem:
 1. Create a parent ClassLoader just for all the Ant libraries and put JUnit
 itself and the entire test classpath in a child classloader.
 2. Run the Launcher class with the sandboxed ClassLoader and have a build
 listener and build logger write the messages and out/err to the filesystem.
 Then to do the assertions, read the files after the fact.
 3. Obtain an Object instance rather than a Project instance and use
 reflection to call the few methods I have to call on it.

 #1 scares me! #2 is defeating much of the purpose of doing all this
 programmatically. #3 ain't pretty, but so far it seems doable.



Re: controlling ClassLoader when programmatically invoking Ant

2012-07-21 Thread Nicolas Lalevée
Hi Mitch,

Le 21 juil. 2012 à 07:37, Mitch Gitman a écrit :

 Technically, this message is better suited for the ant-user list, but I'm
 thinking I'm more apt to get an answer on this list. (I'm also thinking
 this is the better place for me to cash in some chits for my having
 submitted patches for three Ivy issues I mentioned recently on this list.
 Subject: extends and buildlist on 2.3.0-rc1)

I am intended to give it a look very soon, I have seen all the activity you 
have done, I don't want to waste it :)

 Here's my problem. I'm trying to do a JUnit test of some Ivy functionality
 (actually, relating to the aforementioned Ivy bugs) by programmatically
 creating and executing an Ant Project object. Everything runs just fine.
 I'm able to execute targets and even tie in a BuildListener and a
 BuildLogger to tap into output and error and check if the build failed.
 
 The problem is, everything works a little too well. Take a look at the
 following example build.xml:
 project xmlns:ivy=antlib:org.apache.ivy.ant name=resolve-test
 default=build
 
target name=build
ivy:settings file=ivysettings.xml /
ivy:resolve ... /
/target
 /project
 
 I've abbreviated the ivy:resolve call, but take it from me that everything
 works, including running the test directly from within an IDE. It
 shouldn't. Nowhere am I specifying the classpath containing the JAR for Ivy
 itself. Nowhere am I even doing the taskdef for Ivy.

In fact, just by writing xmlns:ivy=antlib:org.apache.ivy.ant, Ant does a 
lookup for the Ivy tasks. It will look for org/apache/ivy/ant/antlib.xml in the 
classpath, derived from the uri definition of the xmlns.
So I guess that in your IDE, it works since you have Ivy in your classpath.

 And in fact, if I run this build.xml straight from the command line, it
 fails like you would expect:
 Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
 ...

This means that the Ivy jar is neither in the Ant classpath ($ANT_HOME/lib/), 
nor in your ant user lib directory ($HOME/.ant/lib).

 I can only think that the key method I want to take advantage of is this in
 Project:
public void setCoreLoader(ClassLoader coreLoader) {
this.coreLoader = coreLoader;
}
 
 What's interesting is that the command-line entry point for Ant in
 org.apache.tools.ant.Main ends up passing null to setCoreLoader, in which
 case the parent classloader should be used, according to the method's
 Javadoc. At this point, I go take a look at the scripts that launch Ant and
 my eyes get blurry. But I believe what I want to do is manually construct a
 ClassLoader as if I were running java -cp ... with the contents of Ant's
 lib directory. (I'm showing my ignorance of ClassLoaders here, I realize.)
 Perhaps someone can point me to an elegant way to accomplish that.

On the command line, the jvm is given only the ant-launcher.jar, it will be the 
content of the system classloader.
Then in org.apache.tools.ant.launch.Launcher.run(String[]), we can see the ant 
Main class is loaded and launched with this classloader:
new URLClassLoader(jars, Launcher.class.getClassLoader());
The system is the parent, the jars listed from $ANT_HOME/lib/, $HOME/.ant/lib 
and other jars from the jvm (tools.jar for instance) will be the content of 
that classloader. This last classloader will be the parent classloader of the 
Project instance.

Now in your IDE, you launch your unit test with every jar listed in your 
classpath, so every thing is already available in the system classlaoder. And 
that system classloader is the parent classloader of the Project instance. So 
lookups works.
So if you want thing to not work, you'll have to build indeed an 
URLClassloader, just like org.apache.tools.ant.launch.Launcher.run does. But 
without any parent classlaoder, otherwise you end up again with the full 
classpath of your project in the IDE.

But If I were you, I wouldn't bother trying to mimic Ant classloading in a unit 
test. The important thing is to be sure that you run against the expected 
version of Ant and Ivy. And relying on the content of a $HOME/.ant/lib is quite 
unsafe.

Nicolas


-
To unsubscribe, e-mail: dev-unsubscr...@ant.apache.org
For additional commands, e-mail: dev-h...@ant.apache.org



Re: controlling ClassLoader when programmatically invoking Ant

2012-07-21 Thread Mitch Gitman
Nicolas, thanks. I was one class off. I was looking at Main and AntMain
when I should have been looking at Launcher. Seeing the type names and the
main method threw me off. And this corroborates my brief follow-up that I
could be doing something with URLClassLoader. Better for me to try to
leverage Launcher though than reinvent that wheel.

Let me see how far I get with that.

I do have to take issue with the one point you make: But If I were you, I
wouldn't bother trying to mimic Ant classloading in a unit test. The
important thing is to be sure that you run against the expected version of
Ant and Ivy.

First, this is not a unit test. It's an integration test or a functional
test, and if it doesn't emulate the real-life behavior in the wild, then
what use is it?

Even if we are treating this as a unit test, you can't really say that
inadvertently picking up everything in the parent ClassLoader is the
equivalent of mocking or stubbing services and components as one normally
does when creating pure unit tests. Consider that there could be a ton of
classes in the IDE's ClassLoader that have nothing whatsoever to do with
the Ant Project being executed.

And this brings me to my last concern. I have already encountered a problem
where some static functionality in some superfluous classes in the
IDE-inherited ClassLoader was causing the JUnit-invoked Project build to
fail.

Even so, to my mind, the uncontrolled success I'm seeing now is no less
troubling than the uncontrolled failure I was seeing then. If you're a
biologist conducting an experiment, you don't want to find out your
cultures were growing only because the Petri dish got contaminated.

On Sat, Jul 21, 2012 at 6:10 AM, Nicolas Lalevée nicolas.lale...@hibnet.org
 wrote:

 Hi Mitch,

 Le 21 juil. 2012 à 07:37, Mitch Gitman a écrit :

  Technically, this message is better suited for the ant-user list, but I'm
  thinking I'm more apt to get an answer on this list. (I'm also thinking
  this is the better place for me to cash in some chits for my having
  submitted patches for three Ivy issues I mentioned recently on this list.
  Subject: extends and buildlist on 2.3.0-rc1)

 I am intended to give it a look very soon, I have seen all the activity
 you have done, I don't want to waste it :)

  Here's my problem. I'm trying to do a JUnit test of some Ivy
 functionality
  (actually, relating to the aforementioned Ivy bugs) by programmatically
  creating and executing an Ant Project object. Everything runs just fine.
  I'm able to execute targets and even tie in a BuildListener and a
  BuildLogger to tap into output and error and check if the build failed.
 
  The problem is, everything works a little too well. Take a look at the
  following example build.xml:
  project xmlns:ivy=antlib:org.apache.ivy.ant name=resolve-test
  default=build
 
 target name=build
 ivy:settings file=ivysettings.xml /
 ivy:resolve ... /
 /target
  /project
 
  I've abbreviated the ivy:resolve call, but take it from me that
 everything
  works, including running the test directly from within an IDE. It
  shouldn't. Nowhere am I specifying the classpath containing the JAR for
 Ivy
  itself. Nowhere am I even doing the taskdef for Ivy.

 In fact, just by writing xmlns:ivy=antlib:org.apache.ivy.ant, Ant does a
 lookup for the Ivy tasks. It will look for org/apache/ivy/ant/antlib.xml in
 the classpath, derived from the uri definition of the xmlns.
 So I guess that in your IDE, it works since you have Ivy in your classpath.

  And in fact, if I run this build.xml straight from the command line, it
  fails like you would expect:
  Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
  ...

 This means that the Ivy jar is neither in the Ant classpath
 ($ANT_HOME/lib/), nor in your ant user lib directory ($HOME/.ant/lib).

  I can only think that the key method I want to take advantage of is this
 in
  Project:
 public void setCoreLoader(ClassLoader coreLoader) {
 this.coreLoader = coreLoader;
 }
 
  What's interesting is that the command-line entry point for Ant in
  org.apache.tools.ant.Main ends up passing null to setCoreLoader, in which
  case the parent classloader should be used, according to the method's
  Javadoc. At this point, I go take a look at the scripts that launch Ant
 and
  my eyes get blurry. But I believe what I want to do is manually
 construct a
  ClassLoader as if I were running java -cp ... with the contents of
 Ant's
  lib directory. (I'm showing my ignorance of ClassLoaders here, I
 realize.)
  Perhaps someone can point me to an elegant way to accomplish that.

 On the command line, the jvm is given only the ant-launcher.jar, it will
 be the content of the system classloader.
 Then in org.apache.tools.ant.launch.Launcher.run(String[]), we can see the
 ant Main class is loaded and launched with this classloader:
 new URLClassLoader(jars, Launcher.class.getClassLoader());
 The system is the parent, the jars 

Re: controlling ClassLoader when programmatically invoking Ant

2012-07-21 Thread Mitch Gitman
Quick update for anyone who's curious.

I'd forgotten that I'd asked much the same question on the ant-user list
back on May 31. This was back when the contamination of the child classpath
with the parent classpath was literally causing the tests to fail. And same
as with this thread, Nicolas L. was kind enough to respond. See thread,
example of correctly consuming an Ant project programmatically.

What's funny (and sad in a way) is that today I went down much the same
path I had laid in the earlier thread without even recollecting that
thread. Here's what I wrote earlier:
***
The one way I may have to tweak this ... is to do:
new URLClassLoader(jars, null);

Passing null for the extra ClassLoader argument obviates the possibility of
the parent classloader creeping in.
***
So this time I actually did this. I created this parentless ClassLoader and
created a Project object from it. And what happened? The moment I tried to
assign this object to a Project variable, I got a ClassCastException:
org.apache.tools.ant.Project cannot be cast to
org.apache.tools.ant.Project. So it's sort of a chicken-and-egg problem.

I also tried just calling Project.setCoreLoader() with this URLClassLoader,
but that didn't change the way the Ivy JAR and such were being loaded.

At this point, I can think of a few ways to address this problem:
1. Create a parent ClassLoader just for all the Ant libraries and put JUnit
itself and the entire test classpath in a child classloader.
2. Run the Launcher class with the sandboxed ClassLoader and have a build
listener and build logger write the messages and out/err to the filesystem.
Then to do the assertions, read the files after the fact.
3. Obtain an Object instance rather than a Project instance and use
reflection to call the few methods I have to call on it.

#1 scares me! #2 is defeating much of the purpose of doing all this
programmatically. #3 ain't pretty, but so far it seems doable.

On Sat, Jul 21, 2012 at 9:33 AM, Mitch Gitman mgit...@gmail.com wrote:

 Nicolas, thanks. I was one class off. I was looking at Main and AntMain
 when I should have been looking at Launcher. Seeing the type names and the
 main method threw me off. And this corroborates my brief follow-up that I
 could be doing something with URLClassLoader. Better for me to try to
 leverage Launcher though than reinvent that wheel.

 Let me see how far I get with that.

 I do have to take issue with the one point you make: But If I were you, I
 wouldn't bother trying to mimic Ant classloading in a unit test. The
 important thing is to be sure that you run against the expected version of
 Ant and Ivy.

 First, this is not a unit test. It's an integration test or a functional
 test, and if it doesn't emulate the real-life behavior in the wild, then
 what use is it?

 Even if we are treating this as a unit test, you can't really say that
 inadvertently picking up everything in the parent ClassLoader is the
 equivalent of mocking or stubbing services and components as one normally
 does when creating pure unit tests. Consider that there could be a ton of
 classes in the IDE's ClassLoader that have nothing whatsoever to do with
 the Ant Project being executed.

 And this brings me to my last concern. I have already encountered a
 problem where some static functionality in some superfluous classes in the
 IDE-inherited ClassLoader was causing the JUnit-invoked Project build to
 fail.

 Even so, to my mind, the uncontrolled success I'm seeing now is no less
 troubling than the uncontrolled failure I was seeing then. If you're a
 biologist conducting an experiment, you don't want to find out your
 cultures were growing only because the Petri dish got contaminated.

 On Sat, Jul 21, 2012 at 6:10 AM, Nicolas Lalevée 
 nicolas.lale...@hibnet.org wrote:

 Hi Mitch,

 Le 21 juil. 2012 à 07:37, Mitch Gitman a écrit :

  Technically, this message is better suited for the ant-user list, but
 I'm
  thinking I'm more apt to get an answer on this list. (I'm also thinking
  this is the better place for me to cash in some chits for my having
  submitted patches for three Ivy issues I mentioned recently on this
 list.
  Subject: extends and buildlist on 2.3.0-rc1)

 I am intended to give it a look very soon, I have seen all the activity
 you have done, I don't want to waste it :)

  Here's my problem. I'm trying to do a JUnit test of some Ivy
 functionality
  (actually, relating to the aforementioned Ivy bugs) by programmatically
  creating and executing an Ant Project object. Everything runs just fine.
  I'm able to execute targets and even tie in a BuildListener and a
  BuildLogger to tap into output and error and check if the build failed.
 
  The problem is, everything works a little too well. Take a look at the
  following example build.xml:
  project xmlns:ivy=antlib:org.apache.ivy.ant name=resolve-test
  default=build
 
 target name=build
 ivy:settings file=ivysettings.xml /
 ivy:resolve ... /
 /target
  

controlling ClassLoader when programmatically invoking Ant

2012-07-20 Thread Mitch Gitman
Technically, this message is better suited for the ant-user list, but I'm
thinking I'm more apt to get an answer on this list. (I'm also thinking
this is the better place for me to cash in some chits for my having
submitted patches for three Ivy issues I mentioned recently on this list.
Subject: extends and buildlist on 2.3.0-rc1)

Here's my problem. I'm trying to do a JUnit test of some Ivy functionality
(actually, relating to the aforementioned Ivy bugs) by programmatically
creating and executing an Ant Project object. Everything runs just fine.
I'm able to execute targets and even tie in a BuildListener and a
BuildLogger to tap into output and error and check if the build failed.

The problem is, everything works a little too well. Take a look at the
following example build.xml:
project xmlns:ivy=antlib:org.apache.ivy.ant name=resolve-test
default=build

target name=build
ivy:settings file=ivysettings.xml /
ivy:resolve ... /
/target
/project

I've abbreviated the ivy:resolve call, but take it from me that everything
works, including running the test directly from within an IDE. It
shouldn't. Nowhere am I specifying the classpath containing the JAR for Ivy
itself. Nowhere am I even doing the taskdef for Ivy.

And in fact, if I run this build.xml straight from the command line, it
fails like you would expect:
Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
...

I can only think that the key method I want to take advantage of is this in
Project:
public void setCoreLoader(ClassLoader coreLoader) {
this.coreLoader = coreLoader;
}

What's interesting is that the command-line entry point for Ant in
org.apache.tools.ant.Main ends up passing null to setCoreLoader, in which
case the parent classloader should be used, according to the method's
Javadoc. At this point, I go take a look at the scripts that launch Ant and
my eyes get blurry. But I believe what I want to do is manually construct a
ClassLoader as if I were running java -cp ... with the contents of Ant's
lib directory. (I'm showing my ignorance of ClassLoaders here, I realize.)
Perhaps someone can point me to an elegant way to accomplish that.

If someone's going to say, Hey, check what antunit does, I'd appreciate
if you could pinpoint what it's doing.

P.S. Perhaps somebody has a rational explanation too for why the taskdef of
Ivy is creeping in.


Re: controlling ClassLoader when programmatically invoking Ant

2012-07-20 Thread Mitch Gitman
P.S. I'm going to give URLClassLoader a shot with the JARs in Ant lib:
http://docs.oracle.com/javase/6/docs/api/java/net/URLClassLoader.html

Almost sounds a little too easy...

On Fri, Jul 20, 2012 at 10:37 PM, Mitch Gitman mgit...@gmail.com wrote:

 Technically, this message is better suited for the ant-user list, but I'm
 thinking I'm more apt to get an answer on this list. (I'm also thinking
 this is the better place for me to cash in some chits for my having
 submitted patches for three Ivy issues I mentioned recently on this list.
 Subject: extends and buildlist on 2.3.0-rc1)

 Here's my problem. I'm trying to do a JUnit test of some Ivy functionality
 (actually, relating to the aforementioned Ivy bugs) by programmatically
 creating and executing an Ant Project object. Everything runs just fine.
 I'm able to execute targets and even tie in a BuildListener and a
 BuildLogger to tap into output and error and check if the build failed.

 The problem is, everything works a little too well. Take a look at the
 following example build.xml:
 project xmlns:ivy=antlib:org.apache.ivy.ant name=resolve-test
 default=build

 target name=build
 ivy:settings file=ivysettings.xml /
 ivy:resolve ... /
 /target
 /project

 I've abbreviated the ivy:resolve call, but take it from me that everything
 works, including running the test directly from within an IDE. It
 shouldn't. Nowhere am I specifying the classpath containing the JAR for Ivy
 itself. Nowhere am I even doing the taskdef for Ivy.

 And in fact, if I run this build.xml straight from the command line, it
 fails like you would expect:
 Problem: failed to create task or type antlib:org.apache.ivy.ant:settings
 ...

 I can only think that the key method I want to take advantage of is this
 in Project:
 public void setCoreLoader(ClassLoader coreLoader) {
 this.coreLoader = coreLoader;
 }

 What's interesting is that the command-line entry point for Ant in
 org.apache.tools.ant.Main ends up passing null to setCoreLoader, in which
 case the parent classloader should be used, according to the method's
 Javadoc. At this point, I go take a look at the scripts that launch Ant and
 my eyes get blurry. But I believe what I want to do is manually construct a
 ClassLoader as if I were running java -cp ... with the contents of Ant's
 lib directory. (I'm showing my ignorance of ClassLoaders here, I realize.)
 Perhaps someone can point me to an elegant way to accomplish that.

 If someone's going to say, Hey, check what antunit does, I'd appreciate
 if you could pinpoint what it's doing.

 P.S. Perhaps somebody has a rational explanation too for why the taskdef
 of Ivy is creeping in.