Akka Camel and Spring - java

I want to combine Akka, Apache Camel, Spring and do not know the way forward for leveraging the three things in the same project.
I was successfully able to
1. write some working code with akka, akka-camel extension and camel routes(Java DSL)
2. use camel and spring (use java DSL but spring for transactions and etc..)
Now I need to combine 1 and 2. Can anyone suggest me the simplest way to achieve this?
EDIT
Some say AKKA no longer supports Spring due to conflict in object instantiation as per the link below
Why spring integration doc for akka exists only for 1.3.1 but not for next versions
Also a similar question is there without a proper solution being presented but the post is about 2 years old
akka-camel 2.2.1 route definition using Spring XML
In one blog post (which I can't get hold of the link right now) a method has been described which is in summary, the actors are defined and used Akka way and what ever the processing Akka actors does to be wired using Spring. But there wasn't any solid example.

I imagine your #2 looks like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ctx="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd >
<!-- Camel route configuration -->
<camelContext id = "testCamelRouteContext" xmlns="http://camel.apache.org/schema/spring">
<route id="test_data_webservice">
<from uri="jetty:http://localhost:8888/myTestService"/>
<log logName="HTTP LOG" loggingLevel="INFO" message="HTTP REQUEST: ${in.header.testdata}"/>
<process ref="myTestService"/>
</route>
</camelContext>
<context:annotation-config />
<bean class="com.package.service" id="myTestService"/>
<bean id="genericDao" class="com.dao.Impl">
<property name="dataSource" ref="datasource" />
</bean>
<bean id="testingDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
datasource stuff
</bean>
</beans>
Is it possible that you can get this camel context through Akka? Something like.
Add in your Akka config:
akka.camel.context-provider="myNewContext"
New ContextProvider class:
class myNewContext extends ContextProvider{
override def getContext(system: ExtendedActorSystem): SpringCamelHybridContext
}
I am guessing this is where the bean injection collision between Spring and Akka could occur. I have never used Akka before so my answer is trivial but I wanted to see if I could provide some help to you.

Reviving an old thread.
akka-springctx-camel library is there to make your life painless to integrate Akka, Spring, Camel, CXF etc.
Add artifact :
<dependency>
<groupId>com.github.PuspenduBanerjee</groupId>
<artifactId>akka-springctx-camel</artifactId>
<version>1.0.0</version>
</dependency>
Add Camel Context Provider in Akka config:
akka.camel.context-provider=system.SpringCamelContextProvider
Get hold of ActorSystem :
implicit val system = SpringContextActorSystemProvider.create
Create a custom RouteBuilder[other way could be Akka Consumer]
class CustomRouteBuilder(system: ActorSystem, echoActor: ActorRef)
extends RouteBuilder {
def configure {
from("direct:testEP")
.routeId("test-route")
.to(echoActor)
}
Get Camel(Spring) Context and add routes to it:
val camel = CamelExtension(system)
camel.context.addRoutes(
new CustomRouteBuilder(system, system.actorOf(Props[EchoActor])))
This test case will give you a detailed idea: https://github.com/PuspenduBanerjee/akka-springctx-camel/blob/master/src/test/scala/AkkaSpringCtxTestSpec.scala

Related

Are we not encouraged to write XML configuration using Maven + Spring?

Currently learning to build spring apps. I have been quite sucessful deploying mock applications for now, but one thing has been annoying me, which is not understanding the mechanisms behind the numerous annotations we add to the code. Look, I'm not saying I don't know which purpose they serve, where they act, nor am I questioning their helpfulness.
My point is that I feel that skipping the changes that should be made (or are being made?) in the XML files actually makes me feel that at the end of the day I don't know what I am truly writing. Let me be more specific, so you could answer me with regards to the following example. This is from Spring manual.
Let’s assume we have the following configuration that defines firstMovieCatalog as the primary MovieCatalog
#Configuration
public class MovieConfiguration {
#Bean
#Primary
public MovieCatalog firstMovieCatalog() { ... }
#Bean
public MovieCatalog secondMovieCatalog() { ... }
// ...
}
With such configuration, the following MovieRecommender will be autowired with the
firstMovieCatalog.
public class MovieRecommender {
#Autowired
private MovieCatalog movieCatalog;
// ...
}
The corresponding bean definitions appear as follows.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<bean class="example.SimpleMovieCatalog" primary="true">
<!-- inject any dependencies required by this bean -->
</bean>
<bean class="example.SimpleMovieCatalog">
<!-- inject any dependencies required by this bean -->
</bean>
<bean id="movieRecommender" class="example.MovieRecommender"/>
</beans>
Okay, so, I think if you can answer me 2 questions regarding this example, It would clear a lot the understanding I am lacking here.
The first thing that is not clear for me: is the annotation process a SEPARATED process from the XML configuration, or is it GENERATING this equivalent XML configuration in some hidden fashion?
Where actually IS this XML configuration file? All spring applications I generated through Initializr just generate the pom.xml file, and it does not include configuration. If I were not using the annotations, would I have to manually write an equivalent configuration in the pom?
is the annotation process a SEPARATED process from the XML configuration, or is it GENERATING this equivalent XML configuration in some hidden fashion?
Spring is not generating any XML or annotation in any case. Spring use XML and annotation processing to get info about which components (classes) are available to use and which beans (instances) to create, inject and use for processing. Then, all these beans could be retrieved by application context (not to confuse with xml of the same name).
Where actually IS this XML configuration file?
Spring first version used XML to configure your app. Later (starting in Spring 3), Spring added annotation support and processing to ease application configuration. Annotations are just another way to configure your components and beans without the hassle of maintaining big XML files (over 1000 lines or even more) or just to avoid dealing with XML at all. Current Spring versions support both configurations, you could also use a mix: using XML and using annotations.
Note that Spring's ApplicationContext has several implementations with different entry points for configuration:
AnnotationConfigApplicationContext accepts a class decorated with #Configuration.
ClassPathXmlApplicationContext accepts the path of a XML file available in application classpath.
If I were not using the annotations, would I have to manually write an equivalent configuration in the pom?
First thing first: POM files are for maven processing, not for Spring. Since you're using Maven, and you want to try using a Spring Boot application without annotations, then you can have this project structure:
- src
- main
- java
/* your Java packages and files */
- com.example
+ App <--- Main entry point
- com.example.service
+ Car <--- Component 1
+ Engine <--- Component 2
- resources
+ my-beans.xml <--- XML configuration. Name can be anything
App class:
package com.example;
import com.example.service.Car;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
#Configuration
#ImportResource("classpath:my-beans.xml")
public class App {
public static void main(String[] args) {
ApplicationContext ctx = SpringApplication.run(App.class, args);
Car car = ctx.getBean(Car.class);
car.move();
}
}
Car.class:
package com.example.service;
public class Car {
private Engine engine;
public void move() {
engine.start();
}
}
Engine.class:
package com.example.service;
public class Engine {
public void start() {
System.out.println("engine starts");
}
}
my-beans.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean class="com.example.service.Engine" />
<bean class="com.example.service.Car" />
<property name="engine" ref="engine"></property>
</bean>
</beans>
is the annotation process a SEPARATED process from the XML configuration, or is it GENERATING this equivalent XML configuration in some hidden fashion
When you initialize a Spring application, you instantiate an ApplicationContext: it's responsible to load all the context definition (the beans, services...).
ApplicationContext is actually an interface which has several implementations depending on how your context is defined:
ClassPathXmlApplicationContext which reads an XML file
AnnotationConfigApplicationContext for annotations based approach
...
Thus you can see it as a unique process, only the datasource is different: either XML or annotations. But they describe the same thing: a context.

JMS Poller Transactional

I am using Spring Integration 4.1.5 and trying to do something with transactions, but unfortunately am not able to and could not find working examples. I'm trying to setup a JMS poller that is looking for messages. Once a message is received, a service activator will insert a row into the database, and the message is passed to another service activator. I would like to make the first two pieces, the message pickup & database insert transactional. I do not want the rest of the flow to be transactional. I am using Weblogic as the application container so will be using the WebLogicJtaTransactionManager.
The problem I'm running into is I am unable to make the first two pieces transactional. It's either all, or nothing. I've tried many methods, but I feel like using an advice-chain on the poller is the best bet. I would be able to control which methods would be part of the transaction.
I've seen examples using a message driven listener, but I am using Weblogic and would be using the Work Managers and I believe I must use a poller in order to take advantage of work managers (if that's not the case, I guess that's another question for the future!)
I've taken the xml and simplified it, but besides editing out the package name, the context produces the issue.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"
xmlns:file="http://www.springframework.org/schema/integration/file"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int-sftp="http://www.springframework.org/schema/integration/sftp"
xmlns:int-xml="http://www.springframework.org/schema/integration/xml"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/file
http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration/sftp
http://www.springframework.org/schema/integration/sftp/spring-integration-sftp.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/xml
http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="jtaTransactionManager"
class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
<property name="transactionManagerName" value="javax.transaction.TransactionManager" />
</bean>
<bean id="insertMessageToDb" class="com.ReadMsgFromAxway" />
<bean id="serviceActivator" class="com.CreateTMDFile" />
<int-jms:inbound-channel-adapter id="jmsDefaultReceiver"
connection-factory="inboundDefaultAdaptorConnectionFactory"
extract-payload="false" destination="inboundAdaptorDefaultListenerQueue"
channel="inboundJMS" acknowledge="transacted">
<int:poller id="poller"
max-messages-per-poll="100" fixed-rate="10">
<int:advice-chain>
<ref bean="txAdvice" />
</int:advice-chain>
</int:poller>
</int-jms:inbound-channel-adapter>
<tx:advice id="txAdvice" transaction-manager="jtaTransactionManager">
<tx:attributes>
<tx:method name="processMessage" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txOperation"
expression="execution(* axway.ReadMsgFromAxway.processMessage(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txOperation" />
</aop:config>
<int:service-activator input-channel="inboundJMS"
output-channel="serviceActivatorChannel" ref="insertMessageToDb" method="processMessage" />
<int:chain input-channel="serviceActivatorChannel" output-channel="nullChannel">
<int:service-activator ref="serviceActivator" />
</int:chain>
</beans>
ReadMsgFromAxway.java
public Message<File> processMessage(Message<?> message) {
//Insert into DB
trackerProcess.insertUpdateMessageTracker(message, "axwayChannel",
"axwayChannel", currentStatusID, null, null);
count++;
int mod = count % 2;
if (mod != 0) {
// pass every 2
String hello = "hey";
} else {
throw new RuntimeException("Testing transactional");
}
Message<File> springMessage = MessageBuilder.createMessage(payloadFile,
messageHeaders);
return springMessage;
}
The XML as is doesn't do anything, whether the runtime exception is thrown, or an exception is thrown at the next service activator component.
If I change the advice attributes to
<tx:method name="*" propagation="REQUIRED"/>
Then the exceptions at the 1st and 2nd service activator causes the rollback.
Oddly enough if I do this
<tx:method name="processMessage" propagation="REQUIRED"/>
<tx:method name="*" propagation="NEVER"/>
Then whether the runtime exception in the 1st service activator, or the 2nd activator is thrown, the message gets rolled back. I would think the pointcut would limit which class would cause the transaction, but I maybe I'm misunderstanding something.
Another note - THis application is housed in an ear file with several other wars. This context starts the entire inbound process, and connects to another war, which contains business logic, via a JMS queue. In the scenario of using method name="*" I saw the exceptions in the business logic war to cause the JMS message of the original inbound message get rolled back too. I was under the impression that the 2nd war would do its processing in another thread, since it receives a message via a queue, and thus not be part of the transaction. Could this be a side effect of JTA, which is container managed?
Thanks!
I'd recommend you to read Dave Syer's article about transaction and there you can find a link in the "More like this".
Right now it looks like you don't understand transactions and AOP at all. You should pay more attention to AOP support in Spring Framework.
In general declarative transactions (#Transactional on method) are the particular cases of AOP advices. The main concept behind any AOP is call stack boundary spawned by the method invocation for which we specify an advice.
But if there is no such a method in the target object, it won't be adviced and wrapped to an AOP proxy. Like in your case for the processMessage when you apply the txAdvice for some internal object around the org.springframework.messaging.Message.MessageSource as a contract of the JmsDestinationPollingSource for that <int-jms:inbound-channel-adapter>.
Instead you can use <transactional> configuration of the <poller>. And right: all the donwstream flow will be covered by transaction.
To finish transaction in this case for that internal
Callable<Boolean> pollingTask = new Callable<Boolean>() {
#Override
public Boolean call() throws Exception {
return doPoll();
}
};
around receive() and handleMessage(), you should just finish the method invocation as in regular #Transactional case. For this purpose we should shit the next message handling to the different thread. Just because by default all <channel>s are DirectChannel and tied with the current call stack.
For this purpose you can just use an ExecutorChannel (<int:dispatcher task-executor="threadPoolExecutor"/>) for that your serviceActivatorChannel.
From there you don't need the rest AOP configuration.
Not sure about your second question for an other web app. Looks like it has some logic to rallback its work in case of some inconsistency from your side. But anyway that looks like a different question.

Why do we use <cxf:rsServer> as opposed to a plain <jaxrs:server> when using the CXF-RS component?

As a follow-up to this question, I'm still a bit confused about how to properly use the CXF-RS component.
I'm confused why we need the <cxf:rsServer> tag for specifying CXF-RS endpoints (or is there even such a concept?), when I can use the <jaxrs:server> tag perfectly fine.
Here's my configuration XML for both Camel and CXF:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:camel="http://camel.apache.org/schema/spring"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd">
<jaxrs:server id="userService" address="/users">
<jaxrs:serviceBeans>
<bean class="com.example.UserServiceNoop" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="user" class="org.apache.camel.component.direct.DirectComponent" />
<camel:camelContext id="someCamelContext">
<camel:route id="userServiceRoute">
<camel:from uri="cxfrs:bean:userService" />
<camel:routingSlip>
<camel:simple>user:${header.operationName}</camel:simple>
</camel:routingSlip>
</camel:route>
<camel:route id="userServiceRetrieveUser">
<from uri="user:retrieveUser" />
<!-- Assume this is going to a useful Processor -->
</camel:route>
</camel:camelContext>
</beans>
UserService.java:
package com.example;
/* a bunch of imports... */
public interface UserService {
#GET
#Path(value="/{user.id}")
#Produces({MediaType.APPLICATION_JSON})
public User retrieveUser(
#PathParam("user.id") Integer id
);
}
UserServiceNoop.java
package com.example;
/* a bunch of imports ... */
public class UserServiceNoop implements UserService
{
#Override
public User retrieveUser(Integer id) {
throw new RuntimeException();
}
}
In this example, I'm not using any <cxf:rsServer> tag, yet it works fine. I know it goes through the CXF-RS component, because when I run the application, it doesn't throw any RuntimeExceptions, which is the expected behavior when using CXF-RS (the method implementation in the service class will not be called).
Am I missing something by not using this tag?
As the other answer says, the cxf:rsServer is mainly used to be processed by a Camel route as in the jaxrs:server the processing of the request is done by a classic controller.
For example:
Classic JAXRS server:
You will declare a classic Bean Rest (Controller) and inject a Service inside.
Sample of an XML config (extract):
<jaxrs:server id="deviceServiceSvcV1" address="/device/v1">
<jaxrs:serviceBeans>
<ref component-id="deviceServiceRest" />
</jaxrs:serviceBeans>
<!-- and other providers, interceptors, etc... here -->
</jaxrs:server>
<!-- Service bean -->
<bean id="deviceServiceRest" class="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
<property name="deviceService" ref="deviceService" />
</bean>
The Controller class will process the request / response in a classic way (e.g. calling an injected service).
Camel route with cxf:rsServer
Sample of an XML config (extract):
<cxf:rsServer id="rsServer" address="/device/v1"
serviceClass="org.mycomp.device.rest.v1.ws.api.DeviceServiceRest">
<cxf:properties>
<!-- whatever here -->
</cxf:properties>
<!-- and other interceptors, etc... here -->
</cxf:rsServer>
and in the classes:
#Produces({ MediaType.APPLICATION_XML })
#Path("/")
public class DeviceServiceRest {
#GET
public Response listDevicess(
#QueryParam("model") String model,
#QueryParam("sid") String sid,
) {
return null; // never used
}
#GET
#Path("{id}")
public Response getDeviceById(
#PathParam("id") String id,
#QueryParam("model") String model,
#QueryParam("sid") String sid
){
return null; // never used
}
}
The REST Controller has empty methods (returning null) but I think the latest camel-cxf supports now an Interface which is more elegant than having methods returning null.
Now, the request processing can be implemented by a Camel Route like this:
from("cxfrs:bean:rsServer?synchronous=true")
.routeId("cxf-device-rest-v1")
.process( new CheckAuthenticationProcessor())
.choice()
.when(header("operationName").isEqualTo("listDevice"))
.setHeader("backenOperation").constant("list")
.setHeader("backendResource").constant("device")
.endChoice()
.when(header("operationName").isEqualTo("getDeviceById"))
.setHeader("backenOperation").constant("retrieve")
.setHeader("backendResource").constant("device")
.endChoice()
.end()
.bean("requestProcessor")
.to(InOut, backendEndpoint)
.process(checkResponseStatusCode())
.bean(new HttpResponseProcessor())
;
And you can also control the request / response processing as you want from the route.
These are two different kind of implementing a REST API (server side) but in my opinion this is a bit old school as modern framework like spring-boot does not need any of these.
I found the second way a bit too much overkill as I like Camel for integration purpose but using it for a REST API could be subject to discussion.
One use-case I can see is a HTTP REST Web-Service for asynchronous processing, the service responding 202 Accepted and the Camel Route making an integration of the request in asynchronous mode especially when a specific Camel Component can be easily used instead of a complex class (or any need of the EIP patterns).
You use cxf:reserver tag when you want to use CXF endpoint as the consumer of something. Say for example in a complex Apache Camel route or in Spring integration. is used when you are the provider of the endpoint serving requests.

springDM Configuration Admin bulk properties change

So, I have springDM managed properties
<beans:beans xmlns="http://www.springframework.org/schema/osgi-compendium"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:osgix="http://www.springframework.org/schema/osgi-compendium"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/osgi-compendium
http://www.springframework.org/schema/osgi-compendium/spring-osgi-compendium.xsd">
<beans:bean id="configurationBean" class="com.eugene.PropertiesBean">
<osgix:managed-properties persistent-id="MyPid" update-strategy="container-managed"/>
<beans:property name="host" value="localhost"></beans:property>
<beans:property name="port" value="5698"></beans:property>
</beans:bean>
</beans:beans>
Now, here is what I do. Deploy the bundle to Virgo, everything works great, the default properties (because the MyPid.properties is not deployed) get injected into the bean.
Deploy MyPid.properties where BOTH host and port are changed, they are both re-injected also.
That's great. But here is the thing, can I have one single method that would tell me that the bean has changed? The properties have been re-injected? Something like : afterPropertiesSet or init in XML config? Because right now having an afterPropertiesSet or init works only the first time the properties get injected, not the second, third and so on... Which is somehow logic.
I do not know (googleed it) if spring DM offers such a thing.
Thx! Eugene.
This is a known issue actually. We had to switch to bean-managed updates.

Apache CXF + Spring: Generating a Simple Client

I've started learning the Apache CXF with Spring. First of all, I've tried to create a simple client/server model.
The server-side is:
service.HelloWorld.java
#WebService
public interface HelloWorld {
String sayHi(String text);
}
service.HelloWorldImpl.java
#WebService(endpointInterface = "service.HelloWorld")
public class HelloWorldImpl implements HelloWorld {
public String sayHi(String text) {
return "Hello, " + text;
}
}
The client-side is:
client.Client.java
public class Client {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[] {"cxf-client-servlet.xml"});
HelloWorld client = (HelloWorld) context.getBean("client");
System.out.println(client.sayHi("Batman"));
}
}
cxf-client-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schema/jaxws.xsd">
<bean id="client" class="service.HelloWorld" factory-bean="clientFactory" factory-method="create"/>
<bean id="clientFactory" class="org.apache.cxf.jaxws.JaxWsProxyFactoryBean">
<property name="serviceClass" value="service.HelloWorld"/>
<property name="address" value="http://localhost:8080/services/HelloWorld"/>
</bean>
The problem is: to make the client work I've had to add service.HelloWorld (package + interface) to the clients's project. I've heard that before using a service I need to generate a stub. So it's confusing for me. So that, what is the correct approach and what is the best practice (may be it is better to use some contract-first approach or suchlike)? Later, I want to add WS-Security, so I need a strong background =)
Thanks in advance.
You can use a simple spring configuration like this for client side -
<jaxws:client id="mywebServiceClient"
serviceClass="com.saurzcode.TestService"
address="http://saurzcode.com:8088/mockTestService">
<jaxws:binding>
<soap:soapBinding version="1.2" mtomEnabled="true" />
</jaxws:binding>
</jaxws:client>
<cxf:bus>
<cxf:outInterceptors>
<bean class="com.saurzcode.ws.caller.SoapHeaderInterceptor" />
</cxf:outInterceptors>
</cxf:bus>
Ignore the Interceptor if you don't need it.
More details in this post.
If you are doing code-first WS development then it is fine to distribute the interface and give it to the client. I believe #WebService is not needed (?) on the interface (only implementation), so the client does not have dependencies on this annotation.
Even if you are doing code-first web-services, you may still download the WSDL document generated for you by Apache CXF and give it to the client instead. With this approach (which is considered more mature, not to mention it can be used on different platforms like .NET) the client has to generate the stubs (using tool like wsdl2java). This process will essentially create very similar client interface automatically.
That's one of the reasons why so many people prefer contract-first development - the same WSDL is used to generate client-side stubs and server-side WS implementation. This limits the scope of (accidental) incompatibilites.

Categories

Resources