0

I've built a project based on the Camel CXF (code first) Tomcat example where the CFX web service is defined by a java interface. In the example, the WS interface is IncidentService.java. In my project the service interface is called Ingester and defines an upload(String body, String id) method. The service deploys to tomcat and I call the service from a client in another project using this code:

ClientProxyFactoryBean factory = new ClientProxyFactoryBean();
                factory.setServiceClass(Ingester.class);
                factory.setAddress(toURL);
                Ingester client = (Ingester) factory.create();
                String out = client.upload(exchange.getIn().getBody(String.class),"2");

The client project references the Ingester interface by importing the server project as a referenced project (in Eclipse).

It all works as expected.

Now I want to deploy just the client on a user machine (and have it still work).

The first approach I simply jar'd the client (using maven). When I run the executable jar I get the error that the ws.Ingester class is not found.

    org.apache.camel.CamelExecutionException: Exception occurred during execution on the exchange: Exchange[ID-VSWINLT019-1541482662292-0-1]
        at org.apache.camel.util.ObjectHelper.wrapCamelExecutionException(ObjectHelper.java:1846)
        at org.apache.camel.impl.DefaultExchange.setException(DefaultExchange.java:385)
        at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:66)
        at org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:548)
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:138)
        at org.apache.camel.processor.Pipeline.process(Pipeline.java:101)
        at org.apache.camel.processor.CamelInternalProcessor.process(CamelInternalProcessor.java:201)
        at org.apache.camel.component.timer.TimerConsumer.sendTimerExchange(TimerConsumer.java:197)
        at org.apache.camel.component.timer.TimerConsumer$1.run(TimerConsumer.java:79)
        at java.util.TimerThread.mainLoop(Unknown Source)
        at java.util.TimerThread.run(Unknown Source)
Caused by: java.lang.NoClassDefFoundError: ws.Ingester 
        at qp.PullRoute$1.process(PullRoute.java:54)
        at org.apache.camel.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:63)
        ... 9 more
Caused by: java.lang.ClassNotFoundException: ws.Ingester

I am not sure which way to go on this and I have tried several approaches with no success.

I'd like to do something like the following which removes the reference to the IncidentService interface:

.to("cxf://http://localhost:8080/data-ingest-service/webservices/ws"
            + "?serviceClass=ws.Ingester"
            + "?serviceName=upload"
            + "?id=1")

Is this the right direction? I get the following exception, how to make it work?

Exception in thread "main" org.apache.camel.RuntimeCamelException: org.apache.camel.FailedToCreateRouteException: Failed to create route route1 at: >>> To[cxf://http://localhost:8080/data-ingest-service/webservices/ws?serviceClass=ws.Ingester?serviceName=upload?id=1] <<< in route: Route(route1)[[From[timer://Timer?period=60000]] -> [OnExcep... because of Failed to resolve endpoint: cxf://http://localhost:8080/data-ingest-service/webservices/ws?serviceClass=ws.Ingester%3FserviceName%3Dupload%3Fid%3D1 due to: ws.Ingester?serviceName=upload?id=1

Could someone give me advice on this please. The 'id' parameter seems to be part of the problem and I am assuming the body will be passed to the body parameter as it does in the code first example above.

I don't feel that packaging up the server and including it as a dependent repository is the correct way to go, mainly because it seems like overkill.

thanks

xindi
  • 27
  • 6

2 Answers2

0

I think it's easiest if you package a war (change the packaging in your pom.xml) with a WEB-INF/web.xml

First step, in your pom.xml:

<packaging>war</packaging>

Now, for your web.xml:

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <display-name>Web Application</display-name>

  <!-- Context loader -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:camel-context.xml</param-value>
  </context-param>

  <!-- CXF servlet -->
  <servlet>
    <servlet-name>CXFServlet</servlet-name>
    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>CXFServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

Then you can run the war in a web container e.g. tomcat.

Alternatively if you want to just run a jar you should look at an imbedded jetty server, or something like that.

vikingsteve
  • 38,481
  • 23
  • 112
  • 156
  • I want to know how to call the remote web service from a java client running a camel route. I don't think packing up the server with the client is the answer. I'd like to invoke the service using .to("cxf://http://...) as described above. Is it possible to invoke the Java first service in this way? Thanks. – xindi Nov 07 '18 at 03:37
  • Right, ok. Is your jar a "jar with dependencies? Google and try that first. – vikingsteve Nov 07 '18 at 07:53
  • Yes it is and running it gives me the exception above. – xindi Nov 08 '18 at 05:05
  • Can you look in the jar and see if `ws` contains `Ingester.class` ? It looks like the dependency classes are not in your jar – vikingsteve Nov 08 '18 at 09:15
  • No it's not there. I tried copying the interface into the client project (knowing that its probably not the way to go) and rebuilding. It then appeared in the jar file but I get `org.apache.cxf.service.factory.ServiceConstructionException: Could not resolve a binding for null`. so I guess copying the file is not the right way to go. I kind of suspect the client needs to have some generated stubs rather than the actual interface. I read that these are generated at compile time? So still looking for the way forward. Thanks for your answer. – xindi Nov 10 '18 at 01:37
  • I removed the server as an included project (Eclipse) and then I created a server jar and added it as a client dependency which compiled. Unfortunately I still get the `could not resolve a binding for null` exception. – xindi Nov 10 '18 at 02:21
  • I just reread your question. Ingester is a web service right? Did you run a codegen on the `wsdl`? If so look under `target` for some generated classes. All of those need to end up in your jar (all of them, not just the interface) – vikingsteve Nov 10 '18 at 19:28
  • Yes, Ingester is a Web service defined by a Java interface. I followed the example CXF code first example which didn't use wsdl. The client works when run from Eclipse and the service is deployed in Tomcat. I've added the server jar as a dependency in the client jar and the generated class file is available. When I run Maven install on the client project the server jar is included however, the assembly plugin seems to be skipping files that are already added, e.g. `META-INF/maven/qws-ingester/qws-ingester/pom.xml already added, skipping` There are allot of these. Could be the issue? – xindi Nov 10 '18 at 21:13
0

I got this working but I'm not convinced it's the best solution. I included the server as a dependency in the client, really is this a good idea? I added Shade plugin stuff to my POM (from this answer Apache CXF client loads fine in Eclipse but standalone jar throws NullpointerException in WSDLServiceFactory)

xindi
  • 27
  • 6