views:

1790

answers:

2

The actual question is: Is there a way to get XmlWebApplicationContext to load resources using paths relative to the context location? For clarity's sake, let's say "context location" is the location of the first file specified via setConfigLocation() method.

Detailed explanation is below:
I'm using Spring MVC in web tier and Spring IOC in mid tier. Appropriate contexts are defined hierarchically as described in Spring Documentation: web stuff is defined in my-servlet.xml and services et al are defined in services.xml that's loaded via ContextLoaderListener. Mid tier can be deployed either together with web tier (e.g. the whole thing runs within ServletContainer) or separately (in which case services.xml is replaced by remote-services.xml defining remote stubs). The whole setup works perfectly except for the following problem:

I have certain resources (additional XML files, what have you) located in the same folder as services.xml that need to be accessible by said services. Those resources are specified as dependencies in services.xml using relative paths. When mid tier is deployed standalone that works fine, but not when it's deployed within servlet container. In the latter case mid tier context gets instantiated as XmlWebApplicationContext which loads all resources based of servlet context root meaning I have to prefix everything with /WEB-INF/ which I'd really like to avoid. Using PropertyPlaceholderConfigurer presents a similar problem as well.

I know I can work around this somewhat by having resources load from classpath, but that's not ideal either - for standalone deployment it means I need to add configuration folder to classpath and for web deployment it means everything has to be copied under WEB-INF/classes.

Any ideas?

+1  A: 

I agree that is rather annoying. I get around this by doing what you suggest, which is putting my spring config on the classpath, so even though I still use fully-qualified imports, they work under any environment.

I'm not sure why your classpath config needs to be that complex, though. The files can just under your java source folder alongside the java files, so they get handled the same.

skaffman
Thank you for the reply. Putting resources alongside java files is perfectly fine in some cases (I do it for Hibernate queries, etc...) but is rather inconvenient for things that can be changed during deployment (like property file used by `PropertyPlaceholderConfigurer`). It has to be accessible (e.g. not inside a jar, etc...) - hence I have to either put it in /WEB-INF/classes or add 'conf' folder it lives in to the classpath during standalone deployment.
ChssPly76
+1  A: 

I've ended up extending Spring's XmlWebApplicationContext to allow relative resource paths. This does what I want, that is allows me to use the same context.xml file no matter whether it's deployed as part of web app or standalone.

For anyone interested source is available below. It's published using SOV (Stack Overflow Voting) license :-) which means you're free to do whatever you want with it as long as you upvote this answer :-)

import java.io.IOException;

import org.springframework.core.io.Resource;
import org.springframework.util.StringUtils;
import org.springframework.web.context.support.XmlWebApplicationContext;

/**
 * Extends Spring's default web application context to allow relative
 * resource paths. Resources without explicitly specified URL protocol
 * and / or leading slash are loaded relative to the first location
 * from getConfigLocations().
 */

public class SpringApplicationContext extends XmlWebApplicationContext {

  @Override
  protected Resource getResourceByPath(String path) {
    path = StringUtils.cleanPath(path);
    if (path.startsWith("/") || (path.indexOf(':')>0)) {
      return super.getResourceByPath(path);
    }
    try {
      return super.getResourceByPath(getConfigLocations()[0])
        .createRelative(path);
    } catch (IOException E) {
      // failed to create relative resource - default to standard implementation
      return super.getResourceByPath(path);
    }
  } // getResourceByPath()
}
ChssPly76