Spring configurations when using a WAR

Hello all,

I’m in the process of creating a CustomTaskChange that calls some common services we use.  All of the hooks for that are already configured in spring as part of our web application.  The idea is that we would package our migration in the war file and using the war file classpath option in from the command line, we would wire our migration with spring.  However we’ve run into a snag.

I’ve tried two different ways to load the context with no luck:

1.  Using ApplicationContext context = new ClassPathXmlApplicationContext( new String[] { “someDir/applicationContext.xml” });
    In this approach, I get that the applicationContext.xml is not found.  I have cracked open the war file to confirm that the file does live at 
    mywar/WEB-INF/classes/someDir/applicationContext.xml.

2.  Using a FileOpener to get a resource as stream and use an XmlBeanDefinitionReader to load the configuration from there.  The issue I’m
    having here is that our applicationContext.xml is really nothing more than a bunch of <import resource… tags that reference other files. 
    Here I get an exception that resources cannot be loaded via an InputStream with relative paths.  The code for this approach looks like this:

GenericApplicationContext context = new GenericApplicationContext();
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(context);
xmlReader.setValidationMode(0);

try {
	InputStream is = fileOpener
			.getResourceAsStream("someDir/applicationContext.xml");
	xmlReader.loadBeanDefinitions(new InputStreamResource(is));
} catch (Exception e) {

                // do some logging here
}
context.refresh();

Am I missing something or is this something that can’t be done with this approach?  Thanks in advance for any help!

Michael

So you are running liquibase from the command line, but needing to get spring bootstrapped?

Classpaths definitly get odd.  When running the war upgrade, what we need to do is extract the war to a temp directory and build up a classloader that uses all the jars in the web-inf/lib dir and the classes in the web-inf/classes dir. 

It seems that option 1 is what you would need to do.  What version of liquibase are you using?

Nathan

Nathan,

Thanks for the response.  I was actually trying to find the unzipped war file that liquibase creates but wasn’t able to find it to see if everything is how I would expect it.  I’m using version 1.9.4.

Thanks,
Michael

Hey,

Quick note, I tried 1.9.5 with the same results.

Michael

So I believe I know what the issue is and it’s actually the relationship between liquibase and Spring.  From what I can gather, when you use the ClassPathXmlApplicationContext to load your context, Spring takes the current context classloader and attempts to load the XML file from there as a classpath resource (see here:  http://forum.springsource.org/showthread.php?t=38369). 

The issue with this, when using the war file classpath option is that a custom classloader is created as part of the process.  That classloader is not the context classloader when Spring goes to load your XML files.  In this case, it can’t find the context files in the current context classloader and bombs.

I’ve emailed Nathan what I think is a fix (it got me around the issue, but I don’t know the wider impact of the change on the framework).  I’ll keep the forum posted on progress.

Thanks,
Michael Minella
http://www.michaelminella.com

Thanks, I got your email and will take a look at it and get it applied. 

Nathan

Thanks for your help Nathan!

Any guestimate on an ETA (or a Jira issue that I can keep tabs on) for the fix to be applied?  No big deal, just determining if we are going to maintain our own tweaked version for a bit or we can rearrange tasks and just wait for the official version.  Any insight you can provide is appreciated.  Thanks in advance!

Michael

I think it looks like a good change.  I committed the fix to trunk.  Thanks for research and the the patch!

Nathan