How to make a SOAP call in Java - java

This seems like it should be simple, but maybe I'm missing something. I just want to make a SOAP call in Java, preferrably using only built-in APIs. I'm a little overwhelmed looking at javax.xml.soap package in the Java documentation. I have tried searching Google, but it seems like all the results are from 2000-2002, and they are all talking about libraries that can be used for SOAP calls (before SOAP libraries were built in, I guess).
I don't need to handle the SOAP request; only make one. This site has an example that is pretty simple, but it doesn't use the built-in Java SOAP libraries. How would I do basically the same thing using core Java?
// Create the parameters
Vector params = new Vector( );
params.addElement(
new Parameter("flightNumber", Integer.class, flightNumber, null));
params.addElement(
new Parameter("numSeats", Integer.class, numSeats, null));
params.addElement(
new Parameter("creditCardType", String.class, creditCardType, null));
params.addElement(
new Parameter("creditCardNumber", Long.class, creditCardNum, null));
// Create the Call object
Call call = new Call( );
call.setTargetObjectURI("urn:xmltoday-airline-tickets");
call.setMethodName("buyTickets");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
call.setParams(params);
// Invoke
Response res = call.invoke(new URL("http://rpc.middleearth.com"), "");
// Deal with the response

Soap has changed a lot since the early days. You can do things like what you describe, but it is not common.
A more common practice now is to use a wsdl2java tool to generate a client API from a WSDL description of the service. That will give you a nice, clean, API to call.
Apache CXF is one place to go for this sort of thing.
One proviso is rpc/encoded. If you are dealing with an old service, it might be rpc/encoded, and in that case your best bet is Apache Axis 1.x. Everything else has run away from rpc/encoded.

The simplest way is soap-ws library:
https://github.com/reficio/soap-ws
SoapClient client = SoapClient.builder()
.endpointUrl("http://rpc.middleearth.com")
.build();
client.post(envelope);

Related

Why does the WebhookResponse builder create wrong key in json?

I'm trying to utilise com.google.cloud.dialogflow.v2.WebhookResponse to interact with my dialogflow agent. But I'm having trouble responding back to the agent during fulfillment.
The response created doesn't follow the specifications required i.e the agent expect the json to be fulfillmentText: "something" but the builder builds it in the format of fulfillment_text. There's not enough documentation on how to use API client correctly
Anyone has experience doing this in java/kotlin?
val response = WebhookResponse
.newBuilder()
.setFulfillmentText("Hello")
.build()
println(response)
println(Gson().toJson(response))
Output:
fulfillment_text: "Hello"
{"bitField0_":0,"fulfillmentText_":"Hello","fulfillmentMessages_":
[],"source_":"","outputContexts_":[],"memoizedIsInitialized":1,"unknownFields":{"fields":{}},"memoizedSize":-1,"memoizedHashCode":0}
I'm using 'com.google.cloud:google-cloud-dialogflow:0.75.1-alpha' from https://cloud.google.com/dialogflow-enterprise/docs/reference/libraries/java
The library you're using is primarily designed as a client library, letting you send text to Dialogflow and having it determine the Intent and parameters (and possibly a response) from that text.
It sounds like you're trying to use this on the other end - in a webhook to handle fulfillment. It just isn't designed for that. The Class was automatically generated from the ProtoBuf definition, which does not serialize to JSON, and isn't designed to represent things that way.
You will need to build the JSON for the response yourself.

Adding soap header authentication to wsdl2java generated code

I'm in the process of creating a Java web services client from a wsdl. I used Eclipses's Dynamic Web Project and new Web Services Client to generate the code with wsdl2java with Apache Axis 1.4. I need to add SOAP authentication to this code in order for it to work with the service. I couldn't find a place to do that in the generated code. After copious research I found this, which I've used as the backbone for my code so far.
Adding ws-security to wsdl2java generated classes
Before I was getting a "Error occurred while processing security for the message" or something along those lines. Now I am getting
"Exception: Did not understand "MustUnderstand" header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security Message: null"
I've tried many things to get past this exception. This is the code I've arrived at now.
javax.xml.namespace.QName headerName = new javax.xml.namespace.QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
org.apache.axis.message.SOAPHeaderElement header = new org.apache.axis.message.SOAPHeaderElement(headerName);
header.setActor(null);
header.setMustUnderstand(true);
// Add the UsernameToken element to the WS-Security header
javax.xml.soap.SOAPElement utElem = header.addChildElement("UsernameToken");
utElem.setAttribute("Id", "uuid-3453f017-d595-4a5b-bc16-da53e5831cd1-1");
javax.xml.soap.SOAPElement userNameElem = utElem.addChildElement("Username");
userNameElem.setValue("username");
javax.xml.soap.SOAPElement passwordElem = utElem.addChildElement("Password");
passwordElem.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElem.setValue("password");
header.setProcessed(true);
// Finally, attach the header to the binding.
setHeader(header)
This code is located in my Binding_ServiceStub class (in its' createCall method).
We have created clients in both C# and VB with this wsdl, and there it's as easy as just changing the ClientCredentials variable which is an extension of the proxy class generated. I was hoping for something similar here.
Here's the security policy from the wsdl code as well.
<wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy>
Does anyone know what else I can do here? Why this exception is happening? I've tried many different combinations of prefixes and setProcesses and setMustUnderstand values all in vain (and based on my research of this exception).
And if anyone knows a way in which to add Soap header authentication to wsdl2java code I would take that too. Just need this to work and you would think something like this would be a little more straightforward or at least have more examples out there.
Update-
Confirmed that the same header passed using SOAPUI works fine. Must be something with the framework? I created a custom handler to process the SOAP Message but that didn't help. Is Axis 1.4 and JAX-RPC the problem? (I know they're outdated but still...)
Cool. I decided to just use Apache CXF as my framework and using this it's as easy as adding
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
bp.getRequestContext().put("ws-security.username", username);
bp.getRequestContext().put("ws-security.password", password);
Wow that's much better. Don't use Axis 1.4 lesson learned.

Odata with Olingo or Odata4j

I'm in over my head.
At the broadest level, I'm trying to expose an Odata interface to an existing pool of data exposed by a service written using Mule. When my Mule service is invoked, if I detect that the URL is Odata format, I want to delegate processing down to something written in Java and then feed the response from that component back to my caller.
I found the Olingo and OData4j libraries. My problem is that these start from building a Web service. But that's too far upstream for me. I have a Web service. What I need to understand are what components I need to implement in order to pass the URL (which I have in hand) onward to an Odata parser which will, in turn, invoke a data provider.
I'm a bit lost with this technology. Can someone point me to a very basic tutorial that clearly delineates this. Or, can they give me a couple steps like: "You have to implement A, B & C and then pass your URL into C.foo()"?
I've tried the Getting Started doc for both libraries but they both start with "first we'll implement a Web service" and don't clearly delineate (to me, at least) where that leaves off and pure Odata sets in.
Thanks.
The following is the code that will help you to get started for using data from a service exposing via OData.(using Apache Olingo).
URL url=new URL(/*your url*/);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty(HttpHeaders.ACCEPT,HttpContentType.APPLICATION_XML);
conn.connect();
InputStream content=conn.getInputStream();
Edm edm = EntityProvider.readMetadata(content, false);
After this you can use static methods of EntityProvider class for carrying out various operations like read,update,write
If you are using odata4j go with the following code
ODataConsumer demo_consumer= ODataConsumers.create(/*your URL*/);
Enumerable<EntitySetInfo> demo_entitySetList = demo_consumer.getEntitySets();
for (EntitySetInfo entitySet : entitySetList) {
System.out.println(entitySet.getHref());
}
this sounds very like how we read rss or other data feeds
Since you have a url, this can be read by a Http Connector or even a polling http connector.
The data can be streamed using a Java input stream the default behavior or converted to a string (object to string).
A simple java component using (OData4j) can process your content .. it sounds like 2 simple components on a mule flow.
R

Want to translate old Java soap.jar style code to something modern

I have some 10 year old Java code for calling a legacy SOAP authentication service. The WSDL is RPC:ENCODED and contains many typos. I was hoping to easily convert the old code to Axis 1.4 or something, but ran into snags. Everything I looked at wanted to use the WSDL. Can someone help translate this into modern code that doesn't require the faulty WSDL?
Here's the SOAP call section:
SOAPMappingRegistry soapmappingregistry = new SOAPMappingRegistry();
BeanSerializer beanserializer = new BeanSerializer();
soapmappingregistry.mapTypes(Constants.NS_URI_SOAP_ENC, new QName(
"urn:xml-soap-session-demo", "authenticationresult"),
AuthenticationResult.class, beanserializer, beanserializer);
Call call = new Call();
call.setSOAPMappingRegistry(soapmappingregistry);
call.setTargetObjectURI("urn:Security");
call.setMethodName("authenticate");
call.setEncodingStyleURI(Constants.NS_URI_SOAP_ENC);
Vector<Object> vector = new Vector<Object>();
vector.addElement(new Parameter("app", String.class, "PHS", null));
vector.addElement(new Parameter("user", String.class, userName, null));
vector.addElement(new Parameter("password", String.class, password, null));
vector.addElement(new Parameter("encryption", Integer.class, new Integer(0), null));
call.setParams(vector);
Response response = null;
URL endpointURL = new URL(endpoint);
response = call.invoke(endpointURL, "");
if (!response.generatedFault()) {
Parameter parameter = response.getReturnValue();
Object obj = parameter.getValue();
...
}
Many thanks.
Well, most soap frameworks relies on the WSDL standard a lot. Axis, CXF, Spring WS etc. I think you could try Spring WS. It has saved me a couple of times when you don't know or want to use the entire WSDL (but knows how the payload should be encoded).
However, why do you even want to port that thing if the service is full of type-o:s? Old client, old service - why don't you keep it that way and upgrade the code once the service has been replaced with something without type-o:s? I don't think you will end up with something less ugly anyway.

ksoap2 complex parameter

I need to call a web service using ksoap2, I have been doign this successfully up till the point where I need to pass a more complex type to the web service.
Does anybody have an example of passing a complex type to a webservice, preferably, only using SoapObject (the object in question is only Strings and dateTimes.
Thanks
in advance
Here is a working tutorial for complex types and arrays with KSOAP . Hope it helps.
Figured out how to do it. Simply used a SoapObject as a property.
I think you can use this android web service client open source tool.
Where you needn't use the soap Object or think with the soap envelop its just like call a method of a service.
say, for a service say ComplexReqService with param ComplexRequest you have to just write :
ComplexReqService service = new ComplexReqService();
CoplextReqPort port = service.getPort();
String resp = port.getResponse ( new ComplexRequest() );
In this way, It will support the complex response as well.

Categories