I'm stumped on a problem trying to consume a ColdFusion SOAP service in Android using kSOAP2. Here is my java code for invoking a test method I've written in ColdFusion (which only returns a string):
private static final String NAMESPACE = "http://www.sub.tv/MyService.cfc?WSDL";
private static String URL = "http://www.sub.tv/MyService.cfc";
private static final String METHOD_NAME = "TestMethod";
private static final String SOAP_ACTION = "http://www.sub.tv/MyService.cfc?method=TestMethod";
public void GetData() {
SoapPrimitive resultstring = null;
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
PropertyInfo inputArgs = new PropertyInfo();
inputArgs.setName("ID");
inputArgs.setValue(1234);
inputArgs.setType(Integer.class);
request.addProperty(inputArgs);
SoapSerializationEnvelope soapenvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
soapenvelope.dotNet = false;
soapenvelope.setOutputSoapObject(request);
AndroidHttpTransport httptransport = new AndroidHttpTransport(URL);
//httptransport.debug = true;
try {
httptransport.call(SOAP_ACTION, soapenvelope);
resultstring = (SoapPrimitive) soapenvelope.getResponse();
} catch (Exception e) {
Log.d(DEBUG, e.getMessage());
}
}
And here is the ColdFusion test method I've written that only returns a string:
<cfcomponent displayname="test_web_service" namespace="http://www.sub.tv">
<cffunction name="TestMethod" returnType = "string" access="remote" description="Test Method">
<cfargument name="ID" type="numeric">
<cfreturn "hello" />
</cffunction>
</cfcomponent>
The error I'm getting when I execute the above Java code is as follows:
org.xmlpull.v1.XmlPullParserException: expected: START_TAG {http://schemas.xmlsoap.org/soap/envelope/}Envelope (position:START_TAG <html>#2:44 in java.io.InputStreamReader#40ff5440)
I suspect the cause of the problem is perhaps the URL I've specified in the SOAP_ACTION but, as far as I know, that's the correct way to invoke a ColdFusion SOAP web service method. Executing that URL in the browser returns the expected results. I've tried excluding the method call in the query string of that URL but I still get the same error.
Any help would be much appreciated.
Thanks for your time,
Tony
Try removing the display name and the namespace. I know neither of these are needed when exposing a web service via CFML. I also suspect that you have an error you're not seeing. Note that in your error it has:
org.xmlpull.... (position:START_TAG <html>#2:44 in java.io.InputStreamReader#40ff5440)
That html tag suggests to me that your web service is throwing an error. When CF does this it outputs HTML. Knowing that, here are a few suggestions. From a browser:
1) access your service directly in the browser: http://www.sub.tv/MyService.cfc. Login to the CF admin and make sure that you see your CFC's documentation.
2) access your WSDL: http://www.sub.tv/MyService.cfc?wsdl. You should see your various functions exposed.
3) access your test function: http://www.sub.tv/MyService.cfc?method=TestMethod&id=123
Actually, since www.sub.tv is public and MyService.cfc is available I tested all of the above for you and it looks like your CFC is good and not throwing errors.
I made a quick test of your CFC:
<cfset test = CreateObject("WebService", "http://www.sub.tv/MyService.cfc?WSDL") />
<cfdump var="#test.TestMethod(123)#" />
This outputs "hello", which is what you'd expect if your Web Service is functioning correctly. This suggests to me that there's an issue in how you're calling it from Android. I've not done much work with Web Services in Java, so I can only be so helpful here.
However, I noticed that your WSDL defines the test method argument as a Double. This is normal for CF since a numeric type can hold any type of number. However, your example code above shows the following:
inputArgs.setType(Integer.class);
Try changing that to Double.class (or whatever this should be in Java to match the argument type.
That's about all I've got for you. Good luck!
I suspect the issue is that you are calling a web service via SOAP but the response is not in the expected format (XML). If you look at the generated output from your web service call http://www.sub.tv/MyService.cfc?method=TestMethod&id=123 you see this:
<wddxPacket version='1.0'>
<header/>
<data>
<string>hello</string>
</data>
</wddxPacket>
This is because By default, ColdFusion serializes all return types (including simple return types), except XML, into WDDX format... from the CFFunction documentation here
Try specifying a returnType of XML in your ColdFusion function and see if that works. You may still need to tweak the output to get what kSOAP is expecting. I don't know the XML format it wants but this should get you started.
Change your CFFunction to something like this:
<cffunction name="TestMethod" returnType="xml" access="remote" description="Test Method">
<cfargument name="ID" type="numeric">
<cfset var xml = "">
<cfxml variable="xml">
<test>hello</test>
</cfxml>
<cfreturn xml>
</cffunction>
Related
I have a situation where I need to store my SOAP response in a string in case of success.
soap(soapActionBuilder -> soapActionBuilder.client("xyzclient").receive().messageType(MessageType.XML).validate("xapth validation", "Success"));
The above code is working if we receive a success response, but now I need to store that SOAP response in a string and return it.
I am not sure how I can do that. if anyone is having any idea please share, I am new to citrus. Thanks in advance.
If you would like to capture some value from response body, you could use a method extractFromPayload. This methods takes two parameters:
path - path to XML element
variable - to store element into variable for further usage in citrus test.
Sample how to use it:
soap().client("client")
.receive()
.extractFromPayload("//Foo/bar","foobar");
Now you can use variable foobar like this ${foobar}
echo("Extracted var: ${foobar}")
public Response getCustomerByName(
#PathParam("customerName") String customerName)
Problem :
I am passing customerName as : stack overflow (URL is encoded as : stack%20overflow). I want to receive as decoded string (stack overflow, without %20) in my java code.
What I tried :
This works perfectly fine, but I felt it is not more generic way of doing it.
URLDecoder.decode(customerName, "UTF-8");
Require more generic solution :
I want to do the similar changes in rest of the APIs as well, so using URLDecoder in each API is burden . Is there any common practice which I can follow to impose this decoding at application level? (#PathParam is already decoded when I receive the request)
It shall be auto "Decoded" and you don't need explicit decoding using URLDecoder.decode(customerName, "UTF-8");
As mentioned in javadoc of PathParam javadoc:
The value is URL decoded unless this is disabled using the Encoded annotation.
I just verified below and it works as per javadoc (in weblogic server)
#GET
#Produces(value = { "text/plain"})
#Path("{customerName}")
public Response getCustomerByName(#PathParam("customerName") String customerName) {
System.out.println(customerName);
return Response.ok().entity(customerName).type("text/plain").build();
}
After researching on google I have not find a working solution for this.
The 'MAVEN by Example' ebook uses the Yahoo weather example. Unfortunately it looks like Yahoo changed their interface. I tried to adapt the java code for this, but get this annoying exception:
exec-maven-plugin:1.5.0:java
Failed to execute goal org.codehaus.mojo:exec-maven-plugin:1.5.0:java
Caused by: org.dom4j.XPathException:
Exception occurred evaluting XPath: /query/results/channel/yweather:location/#city.
Exception: XPath expression uses unbound namespace prefix yweather
The xml line itself is:
<query xmlns:yahoo="http://www.yahooapis.com/v1/base.rng" yahoo:count="1" yahoo:created="2017-02-13T10:57:34Z" yahoo:lang="en-US">
<results>
<channel>
...
<yweather:location xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" city="Theale" country="United Kingdom" region=" England"/>
The entire XML can be generated from :
https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%3D91731537
My code (as per the 'MAVEN By Example' ebook, xpath and url modified for the changed Yahoo):
public Weather parse(InputStream inputStream) throws Exception {
Weather weather = new Weather();
SAXReader xmlReader = createXmlReader();
Document doc = xmlReader.read( inputStream );
weather.setCity(doc.valueOf ("//yweather:location/#city") );
// and several more, such as setCountry, setTemp
}
(I'm not an xpath expert, so I tried
/query/results/channel/item/yweather:location/#city
as well, just in case, with the same result.
xmlReader:
public InputStream retrieve(String woeid) throws Exception {
String url = "https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%3D"+woeid; // eg 91731537
URLConnection conn = new URL(url).openConnection();
return conn.getInputStream();
}
and the weather class is just a set of getters and setters
When I try this in this XML tester, it works just fine, but that may be the effect of XPATH-v2 vs Java's v1.
When you evaluate your XPath //yweather:location/#city, the XPath processor has no knowledge of which namespace the yweather prefix is bound to. You'll need to provide that information. Now, you might think "the info is right there in the document!" and you'd be right. But prefixes are just a sort of stand-in (like a variable) for the actual namespace. A namespace can be bound to any prefix you like that follows the prefix naming rules, and can be bound to multiple prefixes as well. Just like the variable name in Java referring to an object is of itself of no importance, and multiple variables could refer to the same object.
For example, if you used XPath //yw:location/#city with the prefix yw bound to namespace http://xml.weather.yahoo.com/ns/rss/1.0, it'd still work the same.
I suggest you use class org.dom4j.xpath.DefaultXPath instead of calling valueOf. Create an instance of it and initialize the namespace context. There's a method setNamespaceURIs that takes a Map from prefixes to namespaces and lets you make the bindings. Bind the above weather namespace (the actual URI) to some prefix of your choosing (may be yweather, but can be anything else you want to use in your actual XPath expression) and then use the instance to evaluate it over the document.
Here's an answer I gave to some question that goes more in-depth about what namespaces and their prefixes really are: https://stackoverflow.com/a/8231272/630136
EDIT: the online XPath tester you used probably does some behind-the-scenes magic to extract the namespaces and their prefixes from the given document and bind those in the XPath processor.
If you look at their sample XML and adjust it like this...
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
<actors>
<actor id="1">Christian Bale</actor>
<actor id="2">Liam Neeson</actor>
<actor id="3">Michael Caine</actor>
</actors>
<foo:singers xmlns:test="http://www.foo.org/">
<test:singer id="4">Tom Waits</test:singer>
<foo:singer id="5">B.B. King</foo:singer>
<foo:singer id="6">Ray Charles</foo:singer>
</foo:singers>
</root>
the XML is semantically equivalent, because the test prefix is bound to the same namespace as foo. The XPath //foo:singer/#id still returns all the right results, so the tool is smart about it. However, it doesn't know what to do with XML...
<root xmlns:foo="http://www.foo.org/" xmlns:bar="http://www.bar.org">
<actors>
<foo:actor id="1">Christian Bale</foo:actor>
<actor id="2">Liam Neeson</actor>
<actor id="3">Michael Caine</actor>
</actors>
<foo:singers xmlns:test="http://www.foo.org/" xmlns:foo="http://www.bar.org">
<test:singer id="4">Tom Waits</test:singer>
<foo:singer id="5">B.B. King</foo:singer>
<foo:singer id="6">Ray Charles</foo:singer>
</foo:singers>
</root>
and XPath //foo:*/#id. The prefix foo is bound to a different namespace in the singers element scope, and now it only returns the ids 5 and 6. Contrast it with this XPath, that doesn't use a prefix but the namespace-uri() function: //*[namespace-uri()='http://www.foo.org/']/#id
That last one returns ids 1 and 4, as expected.
I found the error, it's my unfamiliarity with namespaces. The 'createXmlReader()'
used in my example above is a method that sets the correct namespace, except that I forgot to change it after Yahoo changed the xml. Careful re-reading the Maven-by-example documentation, the generated error, and comparing with the detailed answer given here, it suddenly clicked. The updated code (for the benefit of anyone trying the same example):
private SAXReader createXmlReader() {
Map<String,String> uris = new HashMap<String,String>();
uris.put( "yweather", "http://xml.weather.yahoo.com/ns/rss/1.0" );
DocumentFactory factory = new DocumentFactory();
factory.setXPathNamespaceURIs( uris );
SAXReader xmlReader = new SAXReader();
xmlReader.setDocumentFactory( factory );
return xmlReader;
}
The only change is in the line 'uris.put()'
Originally the namespace was "y", now it is "yweather".
when using the below code using XML it works perfectly, that is, the navigation links are returned successfully. However, when I change the format to "json" or "application/json", the links2 navigation links list is empty, meaning that rental.getNavigations() returns an empty list.
Can anyone help please? I am using Apache Olingo for Java OData v4.
Thanks
URI uri = client.newURIBuilder(serviceRoot)
.appendEntitySetSegment("Rentals")
.appendKeySegment(1).format("application/xml").build();
ODataRetrieveResponse<ODataEntity> response2 = client.getRetrieveRequestFactory().getEntityRequest(uri).execute();
ODataEntity rental = response2.getBody();
List<ODataLink> links2 = rental.getNavigationLinks();
for (ODataLink link : links2) {
System.out.println(link.getRel());
System.out.println(link.getName());
URI linkUri = client.newURIBuilder(serviceRoot)
.appendNavigationSegment(link.getLink().toString()).format("atom").build();
ODataRetrieveResponse<ODataEntity> responseCustomer
= client.getRetrieveRequestFactory().getEntityRequest(linkUri).execute();
ODataEntity cust = responseCustomer.getBody();
if(link.getName().equals("Stock"))
System.out.println(cust.getProperty("Status").getValue().toString());
else System.out.println(cust.getProperty("Name").getValue().toString());
}
The odata.metadata=full format parameter is necessary to get odata.navigationLink properties to appear in the JSON response. Add odata.metadata=full to the format option when building the client. The full format should be application/json;odata.metadata=full. If you have access to the request headers via the client object, you might consider setting the Accept header instead.
I have problem in getting the exact value passed from android using post method to php.
I am passing this String from Android using http post :
String secret = "mtHa5YRivVrQ/ZNtoe2oxg==";
In the php I am getting this:
$secret = $_POST['secret'];
echo $secret
Output : mtHa5YRivVrQ\/ZNtoe2oxg==
You can see that in php it has added '\' after '/'. Why this is happening I don't understand. I want the exact string that I have passed from Android.
try this...
if (get_magic_quotes_gpc()) {
$secret = stripslashes($_POST['secret']);
}
or use PHP latest version....