3

I have a web-service (with Spring-WS).

I have a jar with several schemas (schema1.xsd, schema2.xsd and schema3.xsd) which I include in my web service.

Is there a way to expose the schemas from the jar through a servlet somehow in my web-service wep app?

My Spring MessageDispatcherServlet is mapped to /ws/

I would like my schemas to be exposed to /schemas/schema1.xsd /schemas/schema2.xsd and so on.

I have an idea how to do it with a servlet, but it's too verbose and there has to be a nicer way.

The way I am thinking is have a servlet filter and everything that hits /schemas/ check if it is in my list of allowed resources and display it.

This has to be a server agnostic solution. (For instance http://tuckey.org/urlrewrite/ will not work).

Thanks.

Alexandru Luchian
  • 2,760
  • 3
  • 29
  • 41
  • Be careful - your resources in WEB-INF/ are protected for a reason. If you build a truly generic solution (which would be slick), you may inadvertantly provide access to any resource in WEB-INF/. Not a bad thing necessarily, but you take this into consideration and consider if and how to limit access to only those resources you intend to serve. – Bert F Apr 06 '10 at 19:20
  • 1
    Spring-WS has nice support for auto-generating a WSDL file based on your schemas, and being able to serve the wsdl. This will by it's nature include the definitions from your xsd files. Are you using this? – matt b Apr 06 '10 at 19:48
  • Wsdl11Definition will use the xsd's just fine. The problem is not in the wsdl, but in the availability of the xsd's. Per say if I want to use SoapUI giving it the wsdl it will fail to load because it will try to load all the xsd's and they will not be there – Alexandru Luchian Apr 06 '10 at 20:47
  • See my 2nd answer for an alternative solution to this problem. – skaffman Apr 06 '10 at 21:22

4 Answers4

3

Me again! Having seen the comments to your original question, I thought I'd offer an alternative solution.

If I understand your problem, it seems you have a WSDL (generated by Spring-WS) which contains references to the various schema. When a client tries to follow those schema references, it fails, because there is no such resource.

Spring-WS offers a nice way out of this, which is described in the section on WSDL exposure:

If you want to use multiple schemas, either by includes or imports, you might want to use the CommonsXsdSchemaCollection, and refer to that from the DefaultWsdl11Definition, like so:

<bean id="schemaCollection" class="org.springframework.xml.xsd.commons.CommonsXsdSchemaCollection">
    <property name="xsds">
        <list>
            <value>classpath:/path/to/schema1.xsd</value>
            <value>classpath:/path/to/schema2.xsd</value>
        </list>
    </property>
    <property name="inline" value="true"/>
</bean>

When the inline property is enabled, it follows all XSD imports and includes, and inlines them in the WSDL. This greatly simplifies the deloyment of the schemas, which still making it possible to edit them separately.

So what you get is a generated WSDL with all of the referenced schemas inlined, so there are no references for the client to follow. It's very slick, and means you don't have to expose your schema files individually.

skaffman
  • 398,947
  • 96
  • 818
  • 769
2

They only way I've found to do this in the past is the have a Spring controller (or servlet, whatever's your poison), which opens a stream to the resource in the JAR (using Class.getResourceAsStream, for example), and then "piping" it to the HTTP response (using Apache Commons IO's IOUtils.copy()).

It's not very nice, but it's a fully generic solution (just parameterise it with the classpath of the resource).

Here's my source for this:

@Controller
public class ResourceController {

    private Resource resource;

    @Required
    public void setResource(Resource resource) {
        this.resource = resource;
    }

    @RequestMapping
    public void handleRequest(HttpServletResponse httpResponse) throws IOException {
        InputStream resourceStream = resource.getInputStream();
        try {
            IOUtils.copy(resourceStream, httpResponse.getOutputStream());
        } finally {
            resourceStream.close();
        }
    }

}
skaffman
  • 398,947
  • 96
  • 818
  • 769
  • I did the same thing with a servlet. For security purposes I need to define the list of xsd's I will allow. I do that via init parameters. Still this solution seems to me to be a hack. I thought there has to be a easier way, a Spring way, but I guess because of security issues it might cause, nobody actually implement any solutions. – Alexandru Luchian Apr 06 '10 at 20:50
  • It feels like a hack, yes, but then the contents of JAR files (and things under `/WEB-INF`) are not *supposed* to be accessible via the client, so you have to go the extra mile. – skaffman Apr 06 '10 at 21:15
  • Apparently there is a simpler solution in Servlet 3.0, see http://stackoverflow.com/questions/4732965/exposing-resources-from-jar-files-in-web-applications-tomcat7. – Björn Pollex Feb 22 '13 at 18:39
0

Just package your XSD's in a war called schemas.war, put in a default web.xml, and deploy the war in whatever web container you use. Its the easiest, code-less way to solve the problem.

Sripathi Krishnan
  • 30,948
  • 4
  • 76
  • 83
0

Sorry, this isn't exactly an "answer" but need 4 more points before I can post a comment. I wanted to get it out here though, and maybe save someone else a lot of the trouble that I just went through.

I discovered that if you only have one xsd, it will get merged into the wsdl when using just the DefaultWsdl11Definition but if you use an <sws:dynamic-wsdl> block to generate the wsdl it just creates a reference to the xsd file which may or may not be what you want. It didn't work for me when trying to use a .NET client to hit the service.

ThatAintWorking
  • 1,330
  • 20
  • 32