I am calling two webservices using spring-integration as shown below:
application-context.xml
<int:chain input-channel="requestChannelForHolidayService"
output-channel="outputChannelForHolidayService">
<int-ws:outbound-gateway
uri="http://localhost:8080/holidayService/holidayService" marshaller="marshaller"
unmarshaller="marshaller" />
</int:chain>
<int:chain input-channel="requestChannelForAccount"
output-channel="outputChannelForAccount">
<int-ws:outbound-gateway
uri="http://localhost:8080/spring-webservices-sample/endpoints"
marshaller="marshaller1" unmarshaller="marshaller1" />
</int:chain>
Testrunner.java
ApplicationContext context = new ClassPathXmlApplicationContext("application-context.xml");
MessageChannel channel=(MessageChannel) context.getBean("requestChannelForHolidayService",MessageChannel.class);
HolidayRequest request=new HolidayRequest();
BigInteger b1=new BigInteger("1");
BigInteger b2=new BigInteger("50");
request.setEmpId(b1);
request.setDays(b2);
System.out.println("sending request");
System.out.println("request sent");
channel.send(MessageBuilder.withPayload(request).build());
ApplicationContext context1 = new ClassPathXmlApplicationContext("application-context.xml");
MessageChannel channel1=(MessageChannel) context1.getBean("requestChannelForAccount",MessageChannel.class);
AccountDetailsRequest request2=new AccountDetailsRequest();
request2.setAccountNumber("12345");
System.out.println("sending request2");
System.out.println("request sent2");
channel1.send(MessageBuilder.withPayload(request2).build());
Now I need to combine the output of 'outputChannelForHolidayService' and 'outputChannelForAccount'.Can anyone help out for acheiving this. Thank you in advance.
You shouldn't use two application contexts; put them in the same context. Set the correlationId header on the messages; send both results to an aggregator with release-strategy-expression="size == 2".
Consider using a Messaging Gateway instead of sending to channels. Something like:
Collection<Object> process(#Payload Object[] requests, #Header("correlationId"), String correlation);
Then in the context, have...
gateway->splitter->payload-type-router->
request1Channel->ws->toAgg
request2Channel->ws->toAgg
toAggChannel->aggregator
If you omit the output-channel from the aggregator, the result will go back to the gateway.
Related
I'm tryng to build the bellow XML message in ESQL and send it in a Soap Request Node, but the webservice is not receiving all the fields. One of them is the DocumentList structure, whose Code and Value are being sent empty. Can you help me?
<tns0:Envelope xmlns:tns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:s00="http://www.outsystems.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tns0:Header/>
<tns0:Body>
<s00:SentEntity>
<s00:EntityRequest>
<s00:Number>2274076</s00:Number>
<s00:EntityName>JOHN SNOW</s00:EntityName>
<s00:EntityCategory>NORMAL</s00:EntityCategory>
<s00:EntityType>PRIVATE</s00:EntityType>
<s00:ActionToDO>Verify</s00:ActionToDO>
<s00:DocumentList>
<s00:DocumentListStructure>
<s00:Code>BI</s00:Code>
<s00:Value>AOLA005510203040</s00:Value>
</s00:DocumentListStructure>
<s00:DocumentListStructure>
<s00:Code>HB</s00:Code>
<s00:Value>AOHB005510203040</s00:Value>
</s00:DocumentListStructure>
</s00:DocumentList>
<s00:DocumentList/>
</s00:EntityRequest>
</s00:SentEntity>
</tns0:Body>
</tns0:Envelope>
you can try:
DECLARE ns NAMESPACE 'http://www.outsystems.com';
DECLARE soapenv NAMESPACE 'http://schemas.xmlsoap.org/soap/envelope/';
SET OutputRoot.XMLNSC.soapenv:Envelope.(XMLNSC.NamespaceDecl)xmlns:soapenv = soapenv;
SET OutputRoot.XMLNSC.soapenv:Envelope.(XMLNSC.NamespaceDecl)xmlns:ns = ns;
SET OutputRoot.XMLNSC.soapenv:Envelope.soapenv:Body.ns:SentEntity.EntityRequest.Number = '2274076';
-- continue...
Im new to camel and would like to change my route dynamically according to some logic preformed before hand
camelContext.addRoutes(new RouteBuilder() {
public void configure() {
PropertiesComponent pc = getContext().getComponent("properties", PropertiesComponent.class);
pc.setLocation("classpath:application.properties");
log.info("About to start route: Kafka Server -> Log ");
from("kafka:{{consumer.topic}}?brokers={{kafka.host}}:{{kafka.port}}"
+ "&maxPollRecords={{consumer.maxPollRecords}}"
+ "&consumersCount={{consumer.consumersCount}}"
+ "&seekTo={{consumer.seekTo}}"
+ "&groupId={{consumer.group}}"
+ "&valueDeserializer=" + BytesDeserializer.class.getName())
.routeId("FromKafka")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println(" message: " + exchange.getIn().getBody());
Bytes body = exchange.getIn().getBody(Bytes.class);
HashMap data = (HashMap)SerializationUtils.deserialize(body.get());
// do some work on data;
Map messageBusDetails = new HashMap();
messageBusDetails.put("topicName", "someTopic");
messageBusDetails.put("producerOption", "bla");
exchange.getOut().setHeader("kafka", messageBusDetails);
exchange.getOut().setBody(SerializationUtils.serialize(data));
}
}).choice()
.when(header("kafka"))
.to("kafka:"+ **getHeader("kafka").get("topicName")** )
.log("${body}");
}
});
getHeader("kafka").get("topicName")
this is what im trying to achieve.
But i dont know how to access the headers value ( which is a map - cause a kafka producer might have more configuration) inside the .to()
I understand i might be using it totally wrong... buts thats what i managed to understand until now...
The main goal is to have multiple message busses as .from()
and multiple message bus options in the .to() that will be decided via an external source (like config file) that way the same route will apply to many logic scenarios
and i thought the choice() method is the best answer
Thanks!
Instead of to(), you can use toD(), which is the "Dynamic To"
See this for details
And for the syntax to use to pull in various headers etc., see the Simple expression page
Hello I have a problem about setting connection timeout.
I use WebServiceTemplate and it has 1 messageSender (CommonsHttpMessageSender).
But is it possible to set different connection timeouts for each URIs(endpoints)?
Sincerely...
public Message sendRequest(OutgoingRequest message, MessageHeaders headers,
EndpointInfoProvider endpointInfoProvider,
WebServiceMessageCallback requestCallback){
Assert.notNull(endpointInfoProvider, "Destination provider is required!");
final Credentials credentials = endpointInfoProvider.getCredentials();
URI destinationUri = endpointInfoProvider.getDestination();
for (WebServiceMessageSender messageSender : webServiceTemplate.getMessageSenders()) {
if (messageSender instanceof CommonsHttpMessageSender) {
HttpClient httpClient = ((CommonsHttpMessageSender) messageSender).getHttpClient();
httpClient.getState().setCredentials(
new AuthScope(destinationUri.getHost(),
destinationUri.getPort(), AuthScope.ANY_REALM,
AuthScope.ANY_SCHEME), credentials
);
httpClient.getParams().setAuthenticationPreemptive(true);
((CommonsHttpMessageSender) messageSender)
.setConnectionTimeout(endpointInfoProvider
.getTimeOutDuration());
}
}
webServiceTemplate.setDestinationProvider(endpointInfoProvider);
//........
}
Spring WS doesn't support different timeouts for different URIs and doesn't plan to add such functionality. Given that your question involves WebServiceTemplate, you can easily configure multiple templates with different timeouts, and use them as desired.
I am new to Restlet framework and I have the following time issue in the post method of my server resource.
My post method code
#Post
public Representation represent(Representation entity){
try{
//Thread.sleep(1000);
long start = System.currentTimeMillis();
Form aForm = new Form(getRequestEntity());
System.err.println("FORM Instantiation TIME: " + (System.currentTimeMillis()-start));
}catch(Exception ex){
ex.printStackTrace();
}
return new StringRepresentation("hello");
}
On different trails, the output that I am getting is 1900-1999 ms. But if I uncomment the line Thread.sleep(1000), then the time output is 900-999 ms. Can any one please confirm what is happening when instantiation the Form object and why the time is always 1900+ ms. Sorting out this time issue is important for me as I have to implement token based authentication to reduce the post method processing time.
Sorry for late reply. The restlet version I am using is 2.0.7
Here is the details
public static void main(String[] args) throws Exception {
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
VirtualHost aHost = component.getDefaultHost();
aHost.attach("/sample", new MyApplication());
component.getLogger().setLevel(Level.OFF);
component.start();
System.err.println("REST SERVICE STARTED ON PORT NUMBER 8182...");
}
I am running this application in local and not in any Web/App Server.
I've a WCF client communicating with an unknown server implementation which I have no control over. This client works fine it just doesn't like, what appears to be, incorrectly formed SOAP Fault messages. The messages I receive look like:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>...</soap:Header>
<soap:Body>
<soap:Fault>
<soap:faultcode>soap:Client</soap:faultcode>
<soap:faultstring>...</soap:faultstring>
<soap:detail>...</soap:detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
I believe according to the soap schema the child elements shouldn't be qualified and ned to look like:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>...</soap:Header>
<soap:Body>
<soap:Fault>
<faultcode>soap:Client</faultcode>
<faultstring>...</faultstring>
<detail>...</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope>
Is there something that I can configure or override so that I can consume messages which arrive in the latter format so that I can consume the fault messages instead of xml exceptions?
I'm cannot recall how I found stumbled across Message Inspectors, but that it how I solved my problem.
This and this article provided the base for creating the inspector, and what follows is the meat of the inspector:
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (!reply.IsFault)
return;
var document = new XmlDocument();
document.Load(reply.GetReaderAtBodyContents());
var navigator = document.CreateNavigator();
var manager = new XmlNamespaceManager(navigator.NameTable);
manager.AddNamespace("soap", "http://schemas.xmlsoap.org/soap/envelope/");
var it = navigator.Select("//soap:Fault", manager);
if (it.MoveNext() && it.Current.HasChildren && it.Current.MoveToChild(XPathNodeType.Element))
{
do
{
var c = it.Current;
if (string.IsNullOrEmpty(c.Prefix))
continue;
c.ReplaceSelf("<" + c.LocalName + ">" + c.InnerXml + "</" + c.LocalName + ">");
/// we may want to record the detail included inside the detail element,
/// it is not reported in the FaultException that is raised.
} while (it.Current.MoveToNext());
}
var reader = XmlDictionaryReader.CreateDictionaryReader(new XmlNodeReader(document));
reader.MoveToStartElement();
var fixedReply = Message.CreateMessage(reply.Version, null, reader);
fixedReply.Headers.CopyHeadersFrom(reply.Headers);
fixedReply.Properties.CopyProperties(reply.Properties);
reply = fixedReply;
}
It looks like the offending application is using a custom (and badly implemented) SOAP library. The following article might help (I haven't had to deal with this as of yet as I am in a pure .Net shop).
http://msdn.microsoft.com/en-us/library/ms733721.aspx
Note that the System.Web.Services.Protocols.SoapHttpClientProtocol class seems significantly more tolerant of malformed Fault responses than WCF.
This is sometimes referred to as ASMX services protocol. That may be an option to consider as well.
Howard Hoffman
} catch (SoapFaultClientException e) {
log.error(e);
SoapFaultDetail soapFaultDetail = e.getSoapFault().getFaultDetail();
SoapFaultDetailElement detailElementChild = (SoapFaultDetailElement) soapFaultDetail.getDetailEntries().next();
Source detailSource = detailElementChild.getSource();
try {
Object detail = (JAXBElement<SearchResponse>) getWebServiceTemplate().getUnmarshaller().unmarshal(detailSource);
// throw new SoapFaultWithDetailException(detail);
} catch (IOException e1) {
throw new IllegalArgumentException("cannot unmarshal SOAP fault detail object: " + soapFaultDetail.getSource());
}
}