roskart / dropwizard-jaxws

Dropwizard bundle that enables building SOAP web services and clients using JAX-WS API
Apache License 2.0
43 stars 36 forks source link

2nd publishEndpoint -> Matching 'endpoint.class' not found #7

Closed chriskessel closed 8 years ago

chriskessel commented 8 years ago

I've got multiple GuiceModules. Each has a chunk of code like this:

        JAXWSBundle jaxwsBundle = new JAXWSBundle("/my/api1");
        bootstrap.addBundle(jaxwsBundle);
        Api1Soap soapApi = new Api1Soap();
        jaxwsBundle.publishEndpoint(new EndpointBuilder("api1Service", soapApi));

The first one works, but the second one (substitute "api2" in place of api1 above) generates an exception:

Exception in thread "main" java.lang.RuntimeException: Error publishing endpoint for service: MainSoapApi: Matching 'endpoint.class' not found.

Each works if they're the only endpoint I publish, but if I publish more than one endpoint the 2nd one fails with that error. Am I use the API wrong somehow?

chriskessel commented 8 years ago

I've watched the chunk of code in JAWSWEnvironment.publishEndpoint() that fails, which is bus.getExtension(). For some reason, on the 2nd call the extensions known to the bus are far fewer than the first time through (14 vs 22 extensions known). I'm not sure how the bus extensions get initialized though, still figuring that out.

chriskessel commented 8 years ago

After much time in the debugger, you can't have two JAXWSBundles. If you have two, there is some sort of deep CXF bus initialization issue and the publishEndpoint() on the 2nd bundle has some problems with pointing at different instance of the CXF bus than the endpoint gets published on (it's, I think, published on the first endpoint). Anyway, some trickiness there I can't figure out a way around.

So, the solution was to publish both endpoints on the same JAXWSBundle. That worked! Except...now there's a clash with the REST endpoints defined. Here's what happens:

    JAXWSBundle jaxwsBundle = new JAXWSBundle("/crk");
    Api1SoapService api1 = new Api1SoapService();
    jaxwsBundle.publishEndpoint(new EndpointBuilder("api1/api1SoapService", api1));
    Api2SoapService api2 = new Api2SoapService();
    jaxwsBundle.publishEndpoint(new EndpointBuilder("api2/api2SoapService", api2));

However, I have a REST endpoint that looks like this: @Path("/crk/foo/bar/baz") public class MyRest ...etc...etc

The JAWSBundles /crk clobbers my REST endpoint that starts with /crk.

If you create the JAWSBundle's endpoint in a way that clobbers the namespace of the REST endpoint, your REST endpoints can't be found. You'll get a "can't find the the request for observer" message.

If the JAXWSBundle has a non-conflicting path (e.g. /crk/api1 is enough to avoid colliding with /crk/foo), then they'll coexist.

    JAXWSBundle jaxwsBundle = new JAXWSBundle("/crk/api1");
    Api1SoapService api1 = new Api1SoapService();
    jaxwsBundle.publishEndpoint(new EndpointBuilder("api1SoapService", api1));

Unfortunately, in my situation I can't then publish multiple endpoints on the same JAWSBundle because they need to be relative to "/crk".

roskart commented 8 years ago

It seems that having multiple JAXWSBundle instances is indeed possible. Each JAXWSBundle has to have its own CXFBus instance (this is already the case). Endpoints have to be published using specific CXFBus (current implementation does not support this). I will commit a fix for this issue in the following days.

chriskessel commented 8 years ago

Cool, I appreciate it. Your project has been great for adding SOAP to our normal REST endpoints in Dropwizard. I've used it a couple times, but this was the first time trying to put in 2 separate SOAP endpoints (trying to replace an old implementation with a new one).

I was going to try and fix it and put in a PR, but I don't know CXF very well :disappointed:

roskart commented 8 years ago

Multiple JAXWSBundle instances are now supported, see commit 768ca77.

chriskessel commented 8 years ago

Thanks!

chriskessel commented 8 years ago

This doesn't seem to have helped :(

I'm still getting the same failure: Exception in thread "main" java.lang.RuntimeException: Error publishing endpoint for service: MainSoapApi: Matching 'endpoint.class' not found.

Here's the way the code works:

public void initialize(Bootstrap boostrap) {
        JAXWSBundle jaxwsBundleA = new JAXWSBundle("/kessel/moduleA/soap/v1");
        bootstrap.addBundle(jaxwsBundleA);
        kessel.moduleA.MainSoapApi mainSoapApiA = new kessel.moduleA.MainSoapApi();
        jaxwsBundleA.publishEndpoint(new EndpointBuilder("dogs", mainSoapApiA));

        JAXWSBundle jaxwsBundleB = new JAXWSBundle("/kessel/moduleB/soap/v1");
        bootstrap.addBundle(jaxwsBundleB);
        kessel.moduleB.MainSoapApi mainSoapApiB = new kessel.moduleA.MainSoapApi();
        // --------->  FAILS on this publishEndpoint()
        jaxwsBundleB.publishEndpoint(new EndpointBuilder("cats", mainSoapApiB));
}
chriskessel commented 8 years ago

I tried moving the publishEndpoint() into the Application.run(), but it still had the same problem just a little later in the lifecycle.

INFO  [2016-03-29 17:15:50,914] org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean: Creating Service {http://blah.blah.blah/}ModuleASoapService from class kessel.moduleA.MainSoapApi
INFO  [2016-03-29 17:15:51,576] org.apache.cxf.endpoint.ServerImpl: Setting the server's publish address to be /dogs
INFO  [2016-03-29 17:15:51,599] org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean: Creating Service {http://blah.blah.blah/}ModuleBSoapService from class kessel.moduleB.MainSoapApi
INFO  [2016-03-29 17:15:51,711] org.apache.cxf.endpoint.ServerImpl: Setting the server's publish address to be /cats
Exception in thread "main" java.lang.RuntimeException: Error publishing endpoint for service: MainSoapApi: Matching 'endpoint.class' not found.
roskart commented 8 years ago

I just tried this code in JaxWsExampleApplication:

    @Override
    public void initialize(Bootstrap<JaxWsExampleApplicationConfiguration> bootstrap) {
        bootstrap.addBundle(hibernate);
        bootstrap.addBundle(jaxWsBundle);
        bootstrap.addBundle(anotherJaxWsBundle);

        JAXWSBundle jaxwsBundleA = new JAXWSBundle("/kessel/moduleA/soap/v1");
        bootstrap.addBundle(jaxwsBundleA);
        jaxwsBundleA.publishEndpoint(new EndpointBuilder("dogs", new SimpleService()));

        JAXWSBundle jaxwsBundleB = new JAXWSBundle("/kessel/moduleB/soap/v1");
        bootstrap.addBundle(jaxwsBundleB);
        jaxwsBundleB.publishEndpoint(new EndpointBuilder("cats", new JavaFirstServiceImpl()));
    }

...and it starts without error. Are you by any chance still running version 0.10.0? Note that 0.10.1 has not been released to maven central yet. Latest version has to be built from sources.

chriskessel commented 8 years ago

Oh, yea, sorry, I'm on version 0.10.0 (I had been on 0.8). I saw a newer version and just assumed that must be the new one. Whoops!

I'll try cloning the repo and building.

chriskessel commented 8 years ago

Got it built and working!

roskart commented 8 years ago

0.10.1 has just been released to Maven central repository.