WSO2 Stream Processor : Correlation during http response handling for http service calls - wso2

I have a hosted http service that accepts a trend data and returns some output. This service is accessed in siddhi query language as follows:
#sink(type='http-request', sink.id='trends',
publisher.url='${SERVICE_URL}', #map(type='json', #payload(""" {"trend":{{trendArray}} } """) ) )
define stream Request(item string, trendArray string);
#source(type='http-response' , sink.id='trends', http.status.code='200',
#map(type='json', #attributes(stock = '<HOW_TO_GET_THIS_VALUE>', output = "<HOW_TO_GET_THIS_VALUE>")
) )
define stream Response(item string, output string);
The http request(and response) payload doesn't include item name.
when the response comes we would like to assign item name against which we scored the output - marked as HOW_TO_GET_THIS_VALUE above.
How to accomplish this in siddhi query ?
How to treat the response data of as-is as pass to the field ?
I did not see a description of this scenario in siddhi. If not supported, it will good to know details of a custom extension (based out of http extension) for this scenario. Solution to add a proxy layer for http call is less desired.

After some experiments , HOW_TO_GET_THIS_VALUE = 'trp:item'. The http sink should also have this field even though its not used in payload.

Related

What type of Request Data can be Retrieved from ColdFusion Headers?

This is a good way to grab the request before the response: useragent = getHttpRequestData().headers["User-Agent"];
What I noticed is that it will not grab the request unless it is on the actual list of header request. An example is I that it seems to only pull the basic request data. For instance if I set the cache control in the web.config file it does set cache, max age and etag, but when setting etags = getHttpRequestData().headers["ETag"]; and trying to output the data for the ETag generated by the web.config file/server it will not grab the ETag data to output. A few others that I tested are:
useragent = getHttpRequestData().headers["User-Agent"];
acceptencoding = getHttpRequestData().headers["Accept-Encoding"];
acceptlanugage = getHttpRequestData().headers["Accept-Language"];
cachecontrol = getHttpRequestData().headers["Cache-Control"];
connection = getHttpRequestData().headers["Connection"];
accept = getHttpRequestData().headers['Accept'];
contentlength = getHttpRequestData().headers['Content-Length'];
Request data is sent from the browser. You can see that with ColdFusion. But IIS sets response headers (such as etag) after ColdFusion is done processing. It's a response not a request. You cannot see that with ColdFusion, but you can in your browser. EX:

Receiving SOAP notifications from eBay api into ASP variable?

I am trying to receive ebay api transaction notifications into an ASP hosted on a web server. The notifications are sent as SOAP messages and can be sent to a URL with a query string. Notifications must be responded to with HTTP 200 OK. I would like the notification to land inside a variable so that I can parse it and send it on to the next part of the system.
http://developer.ebay.com/DevZone/guides/ebayfeatures/Notifications/Notifications.html#ReceivingPlatformNotifications
In the documentation they mention that this is possible, but the sample they give goes the route of subscribing to an email server. This ASP would not necessarily need to make SOAP requests, just accept SOAP messages from the ebay servers.
I am studying ASP, SOAP, and query strings, but a little guidance would be truly appreciated. Thanks!
This should be pretty straight forward, your Classic ASP page becomes the endpoint for the eBay Notification API (as long as you have configured it to send notifications and what URL to send them to).
You should be able to test this with a simple Classic ASP page
<%
Dim isPost: isPost = (UCase(Request.ServerVariables("REQUEST_METHOD") & "") = "POST")
Dim hasSoapAction
'Is it a HTTP POST?
If isPost Then
'Do we have a SOAPACTION header (check both because
'it can be either HTTP_ or HEADER_ depending on IIS version)?
hasSoapAction = ( _
Len(Request.ServerVariables("HEADER_SOAPACTION") & "") > 0 Or _
Len(Request.ServerVariables("HTTP_SOAPACTION") & "") > 0 _
)
If hasSoapAction Then
'Process the notification here.
'Use Request.BinaryRead to read the SOAP
End If
'Let eBay know we have received and processing the message.
Response.Status = "200 OK"
Else
'Return method not allowed
Response.Status = "405 Method Not Allowed"
End If
Response.End
%>
You might also want to check REMOTE_HOST to make sure that you are only getting sent messages for the expected source (this isn't bulletproof though as the information can be spoofed).
Useful Links
Accessing a request's body (great existing answer that explains how to use Request.BinaryRead() to read the content and convert it to a string which you can then use in a variable or for parsing with XMLDocument.LoadXML()).
How to generate MD5 using VBScript in classic ASP? (If you want to look at a way of verifying the MD5 signature)
This is what i have so far in my notifications.asp. When I try to send it a basic SOAP post through Postman nothing is happening. Does this look like it should work?
I tested this without the If statements checking for SOAP headers, and I posted just regular string data and it works. So the binary to string conversion and output to file is all good. Now I just need to test it with actual ebay api notifications. ;-)
<%
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "iso-8859-1"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function
Dim isPost: isPost = (UCase(Request.ServerVariables("REQUEST_METHOD") & "") = "POST")
Dim hasSoapAction
'Is it a HTTP POST?
If isPost Then
'Do we have a SOAPACTION header?
hasSoapAction = (Len(Request.ServerVariables("HEADER_SOAPACTION") & "") > 0)
If hasSoapAction Then
'Process the notification here.
'Use Request.BinaryRead to read the SOAP
If Request.TotalBytes > 0 Then
Dim lngBytesCount, text
lngBytesCount = Request.TotalBytes
text = BytesToStr(Request.BinaryRead(lngBytesCount))
dim fs, tfile
set fs=Server.CreateObject("Scripting.FileSystemObject")
set tfile=fs.CreateTextFile("C:\inetpub\wwwroot\ASPtest\notifications.txt")
tfile.WriteLine(text)
tfile.Close
set tfile=nothing
set fs=nothing
End If
End If
'Let eBay know we have received and processing the message.
Response.Status = "200 OK"
Else
'Return method not allowed
Response.Status = "405 Method Not Allowed"
End If
Response.End
%>

Unable to set headers in apex web service callouts in salesforce

I'm currently trying to call Amazon Product Retail Web Service in Salesforce.
As I mentioned in
Getting WSDL parse error while generating Apex code from WSDL in Salesforce
I was initially unable to generate apex stub class, but I followed the method suggested by #Ballinger and created apex class. I wrote an apex class to use that stub and to set request parameters. The class i wrote is as follows
public class AmazonProductStubNew
{
public static void getResults()
{
System.Debug(' getResults start ');
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
stub.inputHttpHeaders_x = new Map<String,String>();
stub.inputHttpHeaders_x.put('AWSAccessKeyId','MyAmazonAWSAccessKeyId');
stub.inputHttpHeaders_x.put('Timestamp','2012-11-28T12:11:30Z');
stub.inputHttpHeaders_x.put('Signature','Encrypted Secret Code');
String MarketplaceDomain = '';
String AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
String AssociateTag = '';
String XMLEscaping = '';
String Validate = '';
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
AmazonWS.ItemSearchResponse_element response = stub.ItemSearch(MarketplaceDomain,AWSAccessKeyId,AssociateTag,XMLEscaping,Validate,Shared,Request);
AmazonWS.Items_element[] localItems = response.Items;
System.Debug(localItems[0].TotalResults);
}
}
Even though I've added HTTP headers to stub, I'm not getting it in XML Request message
XML Request is as follows
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header />
<env:Body>
<ItemSearch xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<MarketplaceDomain>
</MarketplaceDomain>
<AWSAccessKeyId>MyAWSAccessKeyId</AWSAccessKeyId>
<AssociateTag></AssociateTag>
<XMLEscaping></XMLEscaping>
<Validate></Validate>
<Shared><SearchIndex>DVD</SearchIndex></Shared>
<Request><Title>Inception</Title>
</Request></ItemSearch>
</env:Body></env:Envelope>
Since headers are not there in SOAP Request, There is a SOAP fault asking for Signature from Amazon Server.
As you can see, I'm new to Salesforce Apex. I followed the steps in
http://www.salesforce.com/us/developer/docs/apexcode/index_Left.htm#StartTopic=Content/apex_web_services_wsdl2apex.htm#http_header_support
to set the headers.
Any idea on why the header isn't getting added?
P.S I added headers manually and tried in SOAP UI, I'm getting proper response.
Thanks :)
I think you're using wrong functions :) (question is indeed confusing).
SOAP (or generally HTTP) communication consists of sending headers and actual message (payload if you like). Headers are short text thingies, message is often a giant XML.
Your code is setting HTTP headers (which are used in web communication to authenticate, provide info about your browser, preferred languages, set cookies, return status codes like 404 page not found...) Please don't be offended with the "for dummies" but I realize the wikipedia article is a bit too much, this might be simpler: http://net.tutsplus.com/tutorials/other/http-headers-for-dummies/
And what I suspect Amazon's webservice wants is just some fields inside the <env:Header>...</env:Header> tag? Just check the generated apex code for existence of subclass called "Header" (you can also search for the variable names like "Signature". This is going to be a total wild guess but I think you'll have to write something like that:
AmazonWS.AWSECommerceServicePortUS stub = new AmazonWS.AWSECommerceServicePortUS();
AmazonWS.Header h = new AmazonWS.Header();
h.AWSAccessKeyId = 'MyAmazonAWSAccessKeyId';
h.Timestamp = '2012-11-28T12:11:30Z';
h.Signature = 'Encrypted Secret Code';
stub.Header = h; // plug it into the request
// create and plug other required tags
AmazonWS.ItemSearchRequest Shared = new AmazonWS.ItemSearchRequest();
Shared.SearchIndex = 'DVD';
AmazonWS.ItemSearchRequest[] Request = new AmazonWS.ItemSearchRequest[1];
Request[0] = new AmazonWS.ItemSearchRequest();
Request[0].Title = 'Inception';
// ...
Now, to make it more confusing you might still have to use a HTTP header, there's a special one called SOAPAction. But generally speaking I believe you're after placing your data in the XML, not in http headers.
Funny enough, I've downloaded the Java example from http://aws.amazon.com/code/Product-Advertising-API/2478 and if I read it correctly they're passing the signature in the URL (endpoint), not in the XML. Probably because it's a REST GET method (if you can access that API it could save you a lot of hair pulled, SOAP is clunky).

CF8 and Salesforce REST API - updating records

I'm trying to do integration with Salesforce using their REST API and CF8.
I got the OAuth bit working, getting data etc but now I'm trying to update some records in Contact table.
First I tought about doing it the "proper" way as their docs say -
Update a record using HTTP PATCH.
But CFHTTP doesn't support PATCH method.
So then I tried running a SOQL query:
UPDATE Contact SET MailingStreet = 'Blah Blah' WHERE Id = '003A000000Zp4ObIAJ'
but here I'm getting
{"message":"unexpected token: UPDATE","errorCode":"MALFORMED_QUERY"}
Does anyone have an idea how to do it?
You can create your own PATCH method if your client supports it, but there is an easier way. From the Force.com REST API Developer's Guide:
If you use an HTTP library that doesn't allow overriding or setting an
arbitrary HTTP method name, you can send a POST request and provide an
override to the HTTP method via the query string parameter
_HttpMethod. In the PATCH example, you can replace the PostMethod line
with one that doesn't use override:
PostMethod m = new PostMethod(url + "?_HttpMethod=PATCH");
In CF9 CFScript, using the method that Paddyslacker already suggested for adding _HttpMethod=PATCH to the URL:
private boolean function patchObject(required string sfid, required string type, required struct obj) {
local.url = variables.salesforceInstance & '/services/data/v' & variables.apiVersion &'/sobjects/' & arguments.type & '/' & arguments.sfid &'?_HttpMethod=PATCH';
local.http = new Http(url=local.url,method='post');
//... convert obj to a json string, add to local.http ...
local.httpSendResult = local.http.send().getPrefix();
}
We have a CF9 CFC that we wrote that wraps most of the REST API that we will be open sourcing soon. I'll come back and link to it when we do.

Dynamic web service request

I'm trying to dynamically send a SOAP request to different webservices. Each webservice has its own ID, so I just basically have to change the ID of the webservice in the URL, E.G.:
http://mywebservice.com/ID/servicedosomething
Anyway, I don't know how to do this manually. I can't reference the services because I would have to add a lot of web references into the app, which doesn't seem very good to do.
Anyway, I just want to know how to construct the SOAP request, send it, and get the result from the service. Btw, I've checked other solutions to similar questions and none worked for me, might be the WP7 framework or something.
Thanks!
From my experience, it is very easy to design and build Windows Phone applications with RESTful web services. In a situation where you only have SOAP XML web services to work with, you will need to do some work within the application to prepare the request, send it and parse the response.
You can store the webservice URL as a string "template" like so -
string wsUrlTemplate = "http://mywebservice.com/{0}/servicedosomething";
When you are about to issue a request, just format the string -
string wsUrl = string.Format(wsUrlTemplate, webServiceID);
If you have the SOAP XML request format, then store it as a template. When you need to issue the request, replace the placeholders with the actual values and send the request (with a POST option, if thats what the web services expect). A typical SOAP XML request template may look like -
string xmlRequestTemplate = "
<?xml version="1.0" encoding="utf-8" ?>
<Customer>
<CustomerID>{0}</Customer>
</Customer>"
To prepare the request XML, you adopt the same approach as above - string format the xmlRequestTemplate and add the CustomerID. To issue the request, use HttpWebRequest to asynchronously issue the request and in the response handler, parse the XML response.
var request = HttpWebRequest.Create(wsUrl);
var result = (IAsyncResult)request.BeginGetResponse(ResponseCallback, request);
private void ResponseCallback(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
var response = request.EndGetResponse(result);
using (var stream = response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
var contents = reader.ReadToEnd();
// Parse the XML response
}
}
Hope this gives you some ideas to proceed.
indyfromoz