How to connect ActiveMQ to CXF with Apache Camel - web-services

does anyone know a working example that bridges ActiveMQ to CXF? I saw many examples that connect a WebService to a message queue, but I need it the other way round. Messages from a JMS queue shall be forwarded to a web service and the result returned to the caller.
My first approach is only working for web services that expose one single method:
from("activemq:wsa").to("cxf:bean:webServiceA");
Status msg = producerTemplate.requestBody("activemq:wsa", params, Status.class);
But for web services that have more than one method, a similar call results in a ExchangeTimedOutException.
Map<String, Object> header = new HashMap<String, Object>();
header.put(CxfConstants.OPERATION_NAME, "doSomething");
header.put(CxfConstants.OPERATION_NAMESPACE, "http://.../");
Status msg = producerTemplate.requestBodyAndHeaders("activemq:wsb", params, header, Status.class);
Nevertheless, I can see that the request is forward to the web service and the correct answer is returned. But unfortunately then it gets lost on its way back.
Any hints or links to external resources are appreciated.
Many regards,
Jakob

ActiveMQ and JMS calls are one way default, you may want to specify it to be synchronous.
http://camel.apache.org/jms.html#JMS-RequestreplyoverJMS
Other than that, it should be no different to use ActiveMQ as a starter for CXF producers.
A suggestion is to download the Camel source and look into this folder:
\components\camel-cxf\src\test\java\org\apache\camel\component\cxf
(or by Web: http://svn.apache.org/viewvc/camel/trunk/components/camel-cxf/src/test/)
You will have a huge amount of CXF producer test cases, to look at as reference material.

The problem occurs when a web service returns objects of classes that don't implement the serializable interface, even if these classes are serializable.
Implementing the serializable interface solves the problem.

Related

Cannot read message on ActiveMQ-queue when implemented in WSO2: "Cannot display ObjectMessage body"

I've just successfully implemented a JMS-message-processor in my WSO2-process. However, when logged in as an admin on the ActiveMQ console, I can view the stats of the queue but I cannot access the contents of the pending message. Instead, I see this error:
Cannot display ObjectMessage body. Reason: Failed to build body from content. Serializable class not available to broker. Reason: java.lang.ClassNotFoundException: org.apache.synapse.message.store.impl.commons.StorableMessage
Accessing the contents of a pending message is possible when using the RabbitMQ, so I figured it should also be possible with this message broker.
I've found solutions online, but they don't seem to be working, or perhaps they're out of date. Can somebody point me to the correct answer to solve this? I'm on WSO2 Integration Studio 8.1.0 and am using ActiveMQ 5.17.1.
It appears that WSO2 is using javax.jms.ObjectMessage despite the fact that there's a long list of reasons why doing so is a bad idea, including the issue you're currently facing, but I digress.
The problem here is that the implementation of the javax.jms.ObjectMessage (i.e. org.apache.synapse.message.store.impl.commons.StorableMessage in this case) must be on the classpath of any application which wants to deserialize that message. This class is not, in fact, on the classpath of ActiveMQ therefore the ActiveMQ web console cannot deserialize the message and display its contents (assuming those contents are human-readable in the first place). That's why a ClassNotFoundException is thrown.
You may be able to resolve the issue by putting org.apache.synapse.message.store.impl.commons.StorableMessage on ActiveMQ's classpath. Aside from that there's really nothing to be done.
I assume this is different for RabbitMQ because in that case WSO2 doesn't use the JMS API and uses the AMQP protocol which is not Java-centric like JMS.
Justin has explained the cause of the issue and as suggested you can try adding the class to ActiveMQ runtime and see whether it resolves the issue. This class is located in the Synapse-Core(synapse-core_2.x.x.wso2vXXX.jar). But remember although this may resolve the ActiveMQ UI issue, this message is not consumable by other systems unless they know how to deserialize it.
Let me add more details on why the message is serialized. Message serialization happens when you use the Store mediator, and when you store a message with Store Mediator it is intended to be only read by a Message Processor. Simply the serialized message can only be consumed by WSO2 Message Processors. In other words, Store Mediator and the Message processors are tightly coupled.
If message serialization is an issue for you. For example, if other systems are consuming the messages that WSO2 publishes you can try using the JMS transport to produce and to consume messages from ActiveMQ. Other than that you can also consider using JMS Inbound Endpoint to consume messages, which all use standard media types when storing the message.

How to invoke a concrete operation of a Mock service deployed in SOAPUI

I have one SoapUI Mock service (served as http://localhost:8454/MyMock) with several operations MockOpA, MockOpB, MockOpC... each of them with his particular unic response.
Is there a way to invoke a particular operation adding it to the URL I used inside the Java code that calls the Mock Service?
Something like http://localhost:8454/MyMock/MockOpA.
I see a lot of examples of one operation several responses; but none of several operations exposed by the same Mock Service.
I have found what I need .....

Truncated Java object when passing through JAX-WS WebService

I am currently working on a project that uses JAX-WS webservices in Java.
The global topic is this : the user creates locally an object, let's say an Agent. He calls a first webservice and passes its Agent to the webservice. The webservice treats the Agent (modifies its properties : e.g. lifepoints), and passes it to another webservice. This call is made from the first webservice, so the user has nothing to do in the process.
After a chain of several webservices, the user retrieves the Agent that has been modified.
The aim of my project is to design 2 parts:
a framework that specifies the behaviour previously described : webservices, Agents and the process of migration
a demo application using my framework. The main difference is the addition of a GUI and a new class Avatar, that extends Agent. So the migration process is still being done "by the framework", with Agent objects.
The following code shows a simple example of how I call my webservice, host my Avatar, then retrieves the agent from the service :
// connection to the server
URL endpoint= new URL("http://SERVER/tomcat/KiwiBidonDynamique/ServiceWebBidonDeDadou?wsdl");
QName serviceName=new QName("http://avatar/","ServeurKiwiBidonService");
Service service = Service.create(endpoint, serviceName);
WebService port = service.getPort(WebService.class);
Avatar myAvatar = new Avatar(1, "Jack the Ripper");
port.hostAgent(myAvatar);
// some process on the service...
Avatar myAvatarTransformed = (Avatar) port.getAgent("AgentNumberOne");
When I do that, I get an exception on the final line :
Exception in thread "main" java.lang.ClassCastException: agent.Agent cannot be cast to avatar.Avatar
After a lot of log reading, I guess the reason is the way the webservice works. When being called, my Avatar given in parameter is marshalled in my JVM then unmarshalled on the service, but the service only constructs an Agent when it unmarshalles. Doing so, it truncates the data specific to the Avatar. Then when I try to retrieve my Agent from the service, it cannot be cast to an Avatar.
Is there a way to keep the Avatar information while processing as an Agent on the service ?
Can I write my own marshalling/unmarshalling somehow ?
Thanks a lot.
If your webservice has Agent element defined as incoming data, then no it is not possible to unmarshall it into an inherited class. I guess it would be possible to write your own marshaller but it is not as easy as it sounds (I would advise against it). Either write a separate WS for each class (messy) or make the incoming data have an element that can store additional structures, like type:any (also messy). The truth is WS are not exactly OO.

Using CAMEL in synchronization with PostgreSQL

I have Spring WS which is creating a record in database after SOAP request, and then it should wait till response appear. (i have two tables in DB - requestTable -record is created when request to WS came, and responseTable - records are created by independent source). When Method detect that record linked with request appear in responseTable, WS send proper response.
Problem lies in synchronization because i can't ( actually i can but i don't want to) create a wait for n seconds thread, i want to make it using CAMEL, I read somewhere that CAMEL implements method that is proper for this kind of situation abut now I can't find it again.
And i have a question for You: Do you have a hint how i can do that?
I will post the way i did this.
Solution with using JMS channel between WS and Database what is described here works great:
Transparent Asynchronous Remoting via JMS

Apache camel to aggregate multiple REST service responses

I m new to Camel and wondering how I can implement below mentioned use case using Camel,
We have a REST web service and lets say it has two service operations callA and callB.
Now we have ESB layer in the front that intercepts the client requests before hitting this actual web service URLs.
Now I m trying to do something like this -
Expose a URL in ESB that client will actually call. In the ESB we are using Camel's Jetty component which just proxies this service call. So lets say this URL be /my-service/scan/
Now on receiving this request #ESB, I want to call these two REST endpoints (callA and callB) -> Get their responses - resA and resB -> Aggregate it to a single response object resScan -> return to the client.
All I have right now is -
<route id="MyServiceScanRoute">
<from uri="jetty:http://{host}.{port}./my-service/scan/?matchOnUriPrefix=true&bridgeEndpoint=true"/>
<!-- Set service specific headers, monitoring etc. -->
<!-- Call performScan -->
<to uri="direct:performScan"/>
</route>
<route id="SubRoute_performScan">
<from uri="direct:performScan"/>
<!-- HOW DO I??
Make callA, callB service calls.
Get their responses resA, resB.
Aggregate these responses to resScan
-->
</route>
I think that you unnecessarily complicate the solution a little bit. :) In my humble opinion the best way to call two independed remote web services and concatenate the results is to:
call services in parallel using multicast
aggregate the results using the GroupedExchangeAggregationStrategy
The routing for the solution above may look like:
from("direct:serviceFacade")
.multicast(new GroupedExchangeAggregationStrategy()).parallelProcessing()
.enrich("http://google.com?q=Foo").enrich("http://google.com?q=Bar")
.end();
Exchange passed to the direct:serviceFacadeResponse will contain property Exchange.GROUPED_EXCHANGE set to list of results of calls to your services (Google Search in my example).
And that's how could you wire the direct:serviceFacade to Jetty endpoint:
from("jetty:http://0.0.0.0:8080/myapp/myComplexService").enrich("direct:serviceFacade").setBody(property(Exchange.GROUPED_EXCHANGE));
Now all HTTP requests to the service URL exposed by you on ESB using Jetty component will generate responses concatenated from the two calls to the subservices.
Further considerations regarding the dynamic part of messages and endpoints
In many cases using static URL in endpoints is insufficient to achieve what you need. You may also need to prepare payload before passing it to each web service.
Generally speaking - the type of routing used to achieve dynamic endpoints or payloads parameters in highly dependent on the component you use to consume web services (HTTP, CXFRS, Restlet, RSS, etc). Each component varies in the degree and a way in which you can configure it dynamically.
If your endpoints/payloads should be affected dynamically you could also consider the following options:
Preprocess copy of exchange passed to each endpoint using the onPrepareRef option of the Multicast endpoint. You can use it to refer to the custom processor that will modify the payload before passing it to the Multicast's endpoints. This may be good way to compose onPrepareRef with Exchange.HTTP_URI header of HTTP component.
Use Recipient List (which also offers parallelProcessing as the Multicast does) to dynamically create the REST endpoints URLs.
Use Splitter pattern (with parallelProcessing enabled) to split the request into smaller messages dedicated to each service. Once again this option could work pretty well with Exchange.HTTP_URI header of HTTP component. This will work only if both sub-services can be defined using the same endpoint type.
As you can see Camel is pretty flexible and offers you to achieve your goal in many ways. Consider the context of your problem and choose the solution that fits you the best.
If you show me more concrete examples of REST URLs you want to call on each request to the aggregation service I could advice you which solution I will choose and how to implement it. The particularly important is to know which part of the request is dynamic. I also need to know which service consumer you want to use (it will depend on the type of data you will receive from the services).
This looks like a good example where the Content Enricher pattern should be used. Described here
<from uri="direct:performScan"/>
<enrich uri="ServiceA_Uri_Here" strategyRef="aggregateRequestAndA"/>
<enrich uri="ServiceA_Uri_Here" strategyRef="aggregateAandB"/>
</route>
The aggregation strategies has to be written in Java (or perhaps some script language, Scala/groovy? - but that I have not tried).
The aggregation strategy just needs to be a bean that implements org.apache.camel.processor.aggregate.AggregationStrategy which in turn requires you to implement one method:
Exchange aggregate(Exchange oldExchange, Exchange newExchange);
So, now it's up to you to merge the request with the response from the enrich service call. You have to do it twice since you have both callA and callB. There are two predefined aggregation strategies that you might or might not find usefull, UseLatestAggregationStrategy and UseOriginalAggregationStrategy. The names are quite self explainatory.
Good luck