I am implementing a Spring MessageListener that is listening to a JMS Queue to process messages containing XML.
My bean ProposalSOAListener will be processing about 5 or more XML messages from the queue. My code is below.
Is there a way to specify different methods on this class to handle different XML messages?
public class ProposalSOAListener implements MessageListener {
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println(((TextMessage) message).getText());
} catch (JMSException ex) {
throw new RuntimeException(ex);
}
}
else {
throw new IllegalArgumentException("Message must be of type TextMessage");
}
}
} // end of ProposalSOAListener class
There's a bunch of architectural questions begged by your question. Do you want this mesasge listener to do the work, or hand it off to another component? Are there transactional considerations at play? Do you have memory constraints - i.e. do you want streaming based XML processing or not? Do
The good news is that you have a lot of the pieces to this puzzle available to you within Spring.
A simple next step would be to use Spring Object XML Marshalling (OXM), choose one of the techniques, and wire the marshaller into your listener bean.
See http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/oxm.html
Another technique would be to use the Spring ApplicationEvent interface, read the messages coming in off the queue and publish them internally to listeners of the specific types. That could be used in combination with the above object marshalling.
Last but not least, if this is SOAP web services - you can take a look at Spring WS, it uses the similar message containers to pull messages off the wire, marshall them, and invoke a spring ws endpoint (ie. the service interface that satisfies that interface contract).
http://static.springsource.org/spring-ws/sites/2.0/reference/html/server.html#d4e907
Spring Integration project is highly recommended for this kind of a problem. Essentially you will have to implement a jms inbound gateway to get your message in. You can then transform this to an object at this point, then route the message to the appropriate service-activator component, which can map to your instance and method.
Related
Our application integration flow is defined as splitter -> ws gateway -> aggregator
The splitter splits request into a list of account numbers; so that for each account number a web service call is initiated and the responses from multiple web service calls are aggregated in the aggregator.The channel between splitter and ws gateway is defined with dispatcher "commonj WorkManagerTaskExecutor" so that each webservice call is initiated parallelly in different threads.
If at least some of the web service call responds properly; even if all other calls result in SoapFault; we need to handle the scenario by using the data from the successful responses with a warning message quoting the error message from the fault response.
The issue is that resolveFault() method of FaultMessageResolver defined in the ws gateway does not return anything and the control never reaches the aggregator if at least one of the parallel web service call fails. Is there any way to handle such a scenario.
You can inject SoapFaultMessageResolver to the <int-ws:outbound-gateway> (fault-message-resolver). This one has pretty simple code:
public void resolveFault(WebServiceMessage message) throws IOException {
SoapMessage soapMessage = (SoapMessage) message;
throw new SoapFaultClientException(soapMessage);
}
So, you failed WS invocation will end up with an Exception.
Add <int-ws:request-handler-advice-chain> to your <int-ws:outbound-gateway> and place there an instance of ExpressionEvaluatingRequestHandlerAdvice. specify its errorChannel and do some agnostic logic in that sub-flow and send some specific message to your aggregator. Don't forget to carry sequenceDetails headers with that messages.
Having all messages in group aggregator will be able to release is as normal one.
In the end you can analyze result List for errors and normal responses.
I have to write a batch (read/process/write) that call a web service (SOAP) as input and then process the result (list of items) to finally write them in a database. How can i call a web service
We did similar thing and here is our approach:
SOAP part:
We used WebServiceTemplate to communicate with SOAP server and method marshalSendAndReceive which basically sends xml request to some url and returns xml response
We use Spring Retry mechanism since SOAP communication is not always reliable so we did setup where we would do each SOAP call at least 5 times until we give up and fail job execution
We use Jaxb2Marshaller for serialization and deserialization and POJO generating from wsdl
Spring batch part:
We implement our own ItemReader where in #BeforeStep we fetch list of items to process from SOAP server (I am not sure if this is best approach but with retry mechanism in place this is robust enough), our #Override of read method is nothing special, it is walking over list until exhausted
In processor we translate SOAP item to DB entity
In writer we do save of items to our own DB
Example:
Item reader is using SoapClient which is my wrapper around web template and it is doing soap call, unmarshalling response and returning list of items.
#Component
#StepScope
public class CustomItemReader implements ItemReader<SoapItem> {
private List<SoapItem> soapItems;
#Autowired
private SoapClient soapClient;
#BeforeStep
public void beforeStep(final StepExecution stepExecution) throws Exception {
soapItems = soapClient.getItems();
}
#Override
public SoapItem read() {
if (!soapItems.isEmpty()) {
return soapItems.remove(0);
}
return null;
}
}
I'm creating my client/server application intercommunication with ServiceStack, and is working great, but I need also to access an external SOAP web service.
I tried to use the Soap12ServiceClient to access it, but I couldn't find any example, and then I went the add service reference WCF way that actually worked, but creating a ton of code.
Is it possible to use Soap12ServiceClient in the same easy way I use JsonServiceClient to send a message/request and receive the message/response? If so, can you help or point me to a sample?
I'm not sure where you're stuck as all of ServiceStack's C# Service Clients implement the same IServiceClient so they can be used in the same way. Here is an example of all of ServiceStack's built-in C# Service Clients calling the same Hello World service:
[TestFixture]
public class HelloWorldServiceClientTests
{
public static IEnumerable ServiceClients
{
get
{
return new IServiceClient[] {
new JsonServiceClient(Config.ServiceStackBaseUri),
new JsvServiceClient(Config.ServiceStackBaseUri),
new XmlServiceClient(Config.ServiceStackBaseUri),
new Soap11ServiceClient(Config.ServiceStackBaseUri),
new Soap12ServiceClient(Config.ServiceStackBaseUri)
};
}
}
[Test, TestCaseSource("ServiceClients")]
public void HelloWorld_with_Sync_ServiceClients(IServiceClient client)
{
var response = client.Send<HelloResponse>(new Hello { Name = "World!" });
Assert.That(response.Result, Is.EqualTo("Hello, World!"));
}
}
Although SOAP works similar to any other C# client, it's un-common to use it in this way because if you're able to use a generic C# SOAP service client you're also likely able to use any of the other service clients which are all faster, more resilient and more versionable than SOAP - which has effectively has no redeeming quality over the other formats other than its ability to generate client proxies which you said you don't want to do anyway.
If you're undecided which endpoint or format you should use I recommend reading my Interview on InfoQ which discusses the disadvantages of SOAP and the benefits of using the other formats.
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.
I currently have a BizTalk 2006 (r1) application which receives XML from a SQL stored proc using the SQL adapter. It maps this to another schema before sending out to a 3rd party. The send port uses a custom pipeline component which converts the XML to a flat file - in the format required by the customer. I don't use any orchestration, this is a pure message based solution.
This all works great when sending via FTP. However, the 3rd party have now requested that I push the message to a web service they hosy. I haven't received the WSDL yet but can assume that the method I'll be calling simply receives a string as a single parameter.
Could anyone advise on the best way to approach this please? I have created a simple web service stub. I then followed Recipe 6-11 from the excellent BizTalk 2006 Recipes book, generating a proxy class using wsdl.exe which I then reference from the "web service" tab of the SOAP send port. However, when processing an order I get the following message in the event log:
Could not load type 'WSProxy' from assembly 'Direct.IS.Payment.Components, Version=3.1.145.0, Culture=neutral, PublicKeyToken=dc03da781bea1472'.".
The type must derive from System.Web.Services.Protocols.SoapHttpClientProtocol.
The type must have the attribute System.Web.Services.WebServiceBindingAttribute. ".
Next step will be for me to play around with the proxy so that it address the derive and attribute issues mentioned in the even log message. However, I can't help but think that there must be an easier way?
Thanks
The custom pipeline component you have created is not producing a message that is suitable for SOAP transmission. Not knowing what the end customer is going to do, I'd hold off on trying ot make SOAP work. In the mean time, just spin up an ASPX page with the following code:
private void Page_Load(object sender, EventArgs e)
{
StreamReader reader = new StreamReader(page.Request.InputStream);
String xmlData = reader.ReadToEnd();
}
Add code to write XMLData to a DB or to a text file or something to see what it is. This is very crude and does not send a response code. It should get you started.