views:

319

answers:

1

I've created a web service client using Axis2. I would like to package the client into a jar, so I can use it in several other projects. The client uses the Axis2 WS-Security module 'rampart'. This module, rampart.mar (not a typo!) has to be present on the Axis 'repository path', in a directory called 'modules'. The client also requires a security policy file, policy.xml. The locations of these last two are injected via Spring, but as they are not subject to change, I would like to package them into the jar.

If you inject a File object like:

<bean id="webserviceStubFactory" class="com.company.WebserviceStubFactory">
    <constructor-arg value="classpath:policy.xml"/>
</bean>

it will work just fine when running/testing the project directly. However, when you package it into a jar, you get

java.io.FileNotFoundException: class path resource [policy.xml] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/path/to/webservice-0.8.jar!/policy.xml

This is a well known Spring 'problem': the constructor-arg is resolved into a Spring ClasspathResource instance and it doesn't support getFile(), because File instances cannot refer to something inside a jar. The solution to this is pretty simple: change the constructor to take a Resource instead of a file and use the InputStream directly. However, this doesn't work for the Axis2 repository path, as I can only specify the full path to the repository and the Axis2 internals figure out where the rampart.mar is located.

So, the question basically boils down to: is it possible to use Spring to inject a path inside a jar (even if it's only /) and have other libraries read from that path as if it were a regular filesystem? I'm guessing it isn't, but I would like to be sure, before installing external 'axis repositories' on the dev/test/production environments and having several copies of the rampart.mar lying around.

+1  A: 

There's only so much that Spring can do to hide the inconsistencies of the underlying JavaSE API. The various getXYZ methods on the Resource interface come with caveats in the documentation, e.g. for getFile():

Throws:
    IOException - if the resource cannot be resolved as absolute file path, 
    i.e. if the resource is not available in a file system

A resource inside a JAR is not "on a filesystem", and so this will never work.

In your case you're going to have to work around Axis2's requirement to operate on files, but manually making sure a file exists. In other words, use Resource.getInputStream() to extract the content of the JAR resource and copy it to a temporary File on the local filesystem, then pass that File to Axis2.

skaffman
The problem is that Axis2 requires a /path/to/ to be given, while it searches for /path/to/modules/rampart.mar. There isn't any file to read in that case. On the other hand, passing a reference to the policy.xml inside the jar works just fine, as I can pass that one as a Resource.In the Axis2 sources I see that it constructs a full URL to find the .mar modules in the Repository, but for some reason it doesn't work. As the amount of time I can spend on this problem is limited, I will probably opt for the ugly solution and just include a rampart.mar in every project that uses this one. :/
Confusion