cannot send parameters from java client - java

I am developing a java client for a web service.
I have this method in my web service:
#WebMethod(operationName = "test")
public Integer test(#WebParam(name = "number")
int number) {
return number;
}
My client looks like this
public static void main(String[] args) {
try {
String BODY_NAMESPACE_VALUE = /namespace url/;
QName port = new QName(/Service name/);
ServiceFactory factory = ServiceFactory.newInstance();
Service service = factory.createService(new QName(/Service name/));
Call call = service.createCall(port);
call.setTargetEndpointAddress(/WSDL location/);
call.setReturnType(XMLType.XSD_INT);
call.setOperationName(new QName(BODY_NAMESPACE_VALUE, "test"));
call.addParameter("number", XMLType.XSD_INT, ParameterMode.IN);
Integer[] i = new Integer[1];
i[0] = new Integer(20);
System.out.println("test :"+call.invoke(i));
} catch (Exception ex) {
ex.printStackTrace();
}
}
I get return values ok from the web service in my java client since I tried getting a constant from the web service. However, in the case above I am trying to send 20 from the client to the web service and receive it back. However I am receiving 0. Does anyone know why sending parameters from client to web service is not working?
Thanks and regards,
Krt_Malta

I don't know if this is the answer but it appears as though you are sending the webservice an array of Integers
Integer[] i;
when it is only expecting a single int.

Related

Is it possible use the Socket API from Java with a Spring-Boot web application?

When I google this subject, all I found is websockets-related stuff. I want use the Socket API from Java to send and receive data between a client and a server (the server is always a spring-boot web application, the client could be or not).
I designed the server application to run on port 4444 when I execute java -jar server.war and the client to run on port 3333 when I execute java -jar client.war. The server should listen on port 5555.
What I have so far, for the server:
controller
#Controller
public class Home {
ServerSocket s;
Integer PORT = 5555;
#RequestMapping("/")
public String index() {
return "index";
}
#RequestMapping("/open_connection")
#ResponseBody
public void open_connection() throws Exception {
s = new ServerSocket(PORT);
}
#RequestMapping("/close_connection")
#ResponseBody
public void close_connection() throws Exception {
s.close();
}
#RequestMapping("/listen_connection")
#ResponseBody
public String listen_connection() throws Exception {
Socket socket = s.accept();
DataInputStream dis=new DataInputStream(socket.getInputStream());
String str = (String) dis.readUTF();
socket.close();
return str;
}
}
the methods are called through this javascript code:
var isOpen = false;
function open_connection(e) {
var url = e.dataset.url;
var oReq = new XMLHttpRequest();
oReq.onload = function(ev) {
var responseText = oReq.response;
isOpen = true;
document.querySelector('.btn-success').style.display = 'none';
document.querySelector('.btn-danger').style.display = 'block';
}
oReq.open("GET", url);
oReq.send();
}
function close_connection(e) {
var url = e.dataset.url;
var oReq = new XMLHttpRequest();
oReq.onload = function(ev) {
var responseText = oReq.response;
isOpen = false;
document.querySelector('.btn-danger').style.display = 'none';
document.querySelector('.btn-success').style.display = 'block';
}
oReq.open("GET", url);
oReq.send();
}
function listen_connection(e) {
var url = document.querySelector('.container').dataset.url;
if(isOpen) {
while(true) {
var oReq = new XMLHttpRequest();
oReq.onload = function(ev) {
var responseText = oReq.response;
if(responseText === 'quit') {
break;
} else {
var item = document.createElement('li');
item.setAttribute('class', 'list-group-item');
item.innerText = responseText
document.querySelector('.list-group').addChild(item);
}
}
oReq.open("GET", url);
oReq.send();
}
}
}
When I call this methods from the html view, open connection and close connection give me no erros. I have no idea how start to listen the connection to receive data from clients (I try call listen_connection from open_connection, but this way I crash the browser when I call the open connection method).
In the client, I have this:
controller
#Controller
public class Home {
String HOST = "localhost";
Integer PORT = 5555;
#RequestMapping("/")
public String index() {
return "index";
}
#RequestMapping(value="/send_data", method=RequestMethod.POST)
#ResponseBody
public void send_data(#RequestParam("data") String data) throws Exception {
Socket socket = new Socket(HOST, PORT);
DataOutputStream dout = new DataOutputStream(socket.getOutputStream());
dout.writeUTF(data);
dout.flush();
dout.close();
socket.close();
}
}
this methods are called through this javascript code:
function send(e) {
var url = e.dataset.url;
var oReq = new XMLHttpRequest();
oReq.onload = function(ev) {
var responseText = oReq.response;
document.querySelector('.form-control').value = '';
}
oReq.open("POST", url);
var formData = new FormData();
formData.append("data", document.querySelector('.form-control').value)
oReq.send(formData);
}
the issue here is that when I click to call this method, I got a error 403 (forbidden).
Anyone can tell me what I am doing wrong here?
The goto would be to use SpringIntegration , TCP & UDP documentation can be found here. But in summary you can use integration flows to transform messages/communication from one form to another, and implement a bunch of standard enterprise integration patterns.
Spring boot application after all is just a java application that usually exposes some Http Interface, but not always (think about some application that gets its input from, say, messaging system).
So technically there is nothing that can prevent you from using plain sockets.
So you can create (probably of scope Singleton so that there will be only one bean like this in the application context). This bean during the initialization would open up a server socket and accept connections.
Since spring boot manages the lifecycle of the application, you can even close gracefully the server socket when the application goes down.
All this will work as long the server socket port is available and you implement the communication protocol by yourself. This the basis. Keep in mind that this way of communication is extremely low-level, so you won't have monitoring, will have to deal with thread pooling (what if there are too many requests on server running in parallel), etc.
Spring Integration or frameworks like Camel can probably wrap it all in a way that you'll be able to actually use that in production, but I think its kind of beyond the scope of the question.

Using ASP.NET Web API to call Java Web Service

I have an ASP.NET Web API which is supposed to call a java addition web service. When i run the java web service and type url http://localhost:8080/addition/9/6 i get {"firstNumber":9,"secondNumber":6,"sum":15}as the output data. Right now, i want to use the ASP.NET Web API to call and display that data when i run the ASP.NET Web API application. How do i go about doing that?
Here are my codes:
ASP.NET Web API Codes
RestfulClient.cs
public class RestfulClient
{
private string BASE_URL = "http://localhost:8080/addition/";
public Task<string> addition()
{
{
try
{
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync("addition").Result;
return response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
HttpContext.Current.Server.Transfer("ErrorPage.html");
}
return null;
}
}
}
ApiController.cs
private RestfulClient restfulClient = new RestfulClient();
public ActionResult Index()
{
var Result1 = restfulClient.addition().Result;
return Content(Result1);
}
Java Web Service Codes
AdditionController.java
#RestController
public class AdditionController {
private static final String template = " %s";
private static int getSum;
#RequestMapping("/addition/{param1}/{param2}")
#ResponseBody
public Addition getSum
(#PathVariable("param1") int firstNumber,#PathVariable("param2") int secondNumber) {
return new Addition(
(String.format(template, firstNumber)), String.format(template, secondNumber));
}
}
Someone please help me. Thank you so much in advance.
According to the Java service, the URL you are calling from the client is not formatted correctly based on your base URL and the one used in the GetAsync.
public class RestfulClient {
private static HttpClient client;
private static string BASE_URL = "http://localhost:8080/";
static RestfulClient() {
client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<string> addition(int a, int b) {
try {
var endpoint = string.Format("addition/{0}/{1}", a, b);
var response = await client.GetAsync(endpoint);
return await response.Content.ReadAsStringAsync();
} catch (Exception e) {
HttpContext.Current.Server.Transfer("ErrorPage.html");
}
return null;
}
}
The controller would also need to be updated.
public async Task<ActionResult> Index() {
int a = 9;
int b = 6;
var result = await restfulClient.addition(a, b);
return Content(result);
}
Note the proper use of the HttpClient as suggested in the comments and as well as the use of async/await.

Persistent and asynchronous stream for communication between appengine/Spring and front-end

At the moment my website is using Spring that handles the http(s) request to and from the front-end like this:
#RestController
public class ComputeController {
#RequestMapping(value = "/api/compute", method = RequestMethod.POST)
public String compute(#RequestBody CodeToken code, OAuth2Authentication OAuth2) {
Map<String, String> userInfo = UserInformation.getUserInfo(OAuth2);
String sourceCode = code.getSource();
String filename = code.getFilename();
String email = userInfo.get("email");
try {
DataStorage dateStorage = new DataStorage();
Compiler compiler = new Compiler(dateStorage);
return compiler.compile(filename, sourceCode, email);
} catch (Exception e) { // TODO Don't catch all exceptions
return e.getStackTrace().toString();
}
}
}
The problem is that I need my front-end (built in Angular) to be able to receive and send information asynchronous from the http(s) request sent from the front-end. Like an continuous I/O stream from the server mid request while the "compiler.compile(...)" is running.
I presume I need to use sockets for this but I'm looking for suggestion on a good way to implement them.
If I understand your intention correctly, you're trying to display some progress in your client while the code compiles. You have two options:
As you proposed, use WebSockets. Spring supports them well. You can see an example here: https://github.com/AlexeySoshin/SpringWebSockets/tree/master/src/main/java/com/alexeysoshin/chat
Instead of blocking your response,
Do compilation on a separate thread pool.
Assign each compilation UUID when you submit this task.
Return the client this task immediately.
Poll another endpoint with UUID

Authentication of type on Header had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id

Have been struggling for last few days with this error Authentication of type {http://service.soap.xcompany.com}AuthenticationHeader had undefined attribute {http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd}Id while invoking a service call from a C# WCF client (targeting .Net 4.5 framework) to a Java Soap Service hosted externally with end-to-end encryption (both client and service certificates are used). When I tested the service using SoapUI with a JKS file, request was processed successfully.
So to see what's difference between the two requests, I did the followings:
Used Fiddler Inspector to capture two requests, one from SoapUI which was successful and one from C# which failed with 500 error
Extracted these two Xml messages into two C# classes (named them RequestByJava and RequestByDotNet, respectively) using the VS2017 feature Edit/Paste Special/Paste Xml as Classes.
Use XmlSerializer to de-serialize the two requests into the two objects of the types created in 2) and compared their properties.
With the Soap error message in mind, I narrowed down the difference between two Authentication headers - interestingly there is one extra property "Id" in the RequestByDotNet object whereas the RequestByJava object does not have. And the 500 Soap error message seemed to indicate that there was a schema validation error due to that undefined element "Id"
Also noticed that the RequestByDotNet.Header.Security.BinarySecurityToken.ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" but RequestByJava (SoapUI) has a different ValueType "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509PKIPathv1"
Another difference, not sure it matters, is that the Request from .net codes has a "mustunderstand" value under the Header.Security set to true while the one from Java does not.
My questions are:
Why is the difference?
How can this be fixed without having to write a Java client?
Some codes used binding and endpoint behavior:
private static CustomBinding BuildCustomBinding()
{
var binding = new CustomBinding();
var textMessageEncoding = new TextMessageEncodingBindingElement()
{
MessageVersion = MessageVersion.Soap11
};
var securityBindingElement =
SecurityBindingElement.CreateMutualCertificateBindingElement(
MessageSecurityVersion.WSSecurity11WSTrustFebruary2005WSSecureConversationFebruary2005WSSecurityPolicy11BasicSecurityProfile10, true);
binding.Elements.AddRange(textMessageEncoding, securityBindingElement, new HttpsTransportBindingElement());
return binding;
}
private static void CallAccountService()
{
//credential for test
const string applId = "testuser";
const string pwd = "password";
//for client certificate, import client.pfx to LocalMachine's Trusted Root Certification Authorities and make sure the thumbprint matches
var client = new NOLWSAccountSvc.WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "thumbprintvalue");
//for service certificate, import service-provider.cer to same store location and store name and make sure the thumbprint matches
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.Root,
X509FindType.FindByThumbprint, "thumprintvalue");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
client.Open();
var header = new NOLWSAccountSvc.AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new NOLWSAccountSvc.getActiveAccounts() { applRef = "softact-dev", resetRows = true };
try
{
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
Thanks for your time! Your help will be highly appreciated.
#jdweng Yes, I did; here were two request bodies, first from .Net and 2nd from SoapUI:
.Net Request:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"><s:Header><h:Authentication u:Id="_2" xmlns:h="http://service.soap.xcompany.com" xmlns="http://service.soap.xcompany.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><application_id>testuserid</application_id><password>testpassword</password></h:Authentication><ActivityId CorrelationId="d7085e6f-b757-46e8-b3eb-319a51d568a3" xmlns="http://schemas.microsoft.com/2004/09/ServiceModel/Diagnostics">00000000-0000-0000-0000-000000000000</ActivityId><VsDebuggerCausalityData xmlns="http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink">uIDPo8DAzaQVkApDpl1Tc1YTHQwAAAAAMbeMEvBLCUqoD7kEDPHDKYukgggNOf5FtHBB/Sa7ggkACQAA</VsDebuggerCausalityData><o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"><o:BinarySecurityToken u:Id="uuid-eb310312-396a-4d00-8922-f77de97138cb-3" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">MIIDYzCCAkugAwIBAgIEaGKzJDANBgkqhkiG9w0BAQsFADBiMQswCQYDVQQGEwJ1czEPMA0GA1UEChMGU3ByaW50MREwDwYDVQQLEwhQcm9qZWN0czEMMAoGA1UECxMDQk1QMQwwCgYDVQQLEwNUUEExEzARBgNV</o:BinarySecurityToken><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><Reference URI="#_1"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>WCpRwVjx89ceVctR8lp9LNGKHeA=</DigestValue></Reference><Reference URI="#_2"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><DigestValue>8/PErh8BL9To5zazpP9CbPFTAa8=</DigestValue></Reference></SignedInfo><SignatureValue>hOtpz7lXvZPPbBD6sV1hxyx3Hc39vj0q2GYKMd8oQbgTbbuKC7QKcZOjktqUxayrzc6h/V0j7Kx3APPONe4F3A2581nK4AQ72yYonsaeXQW0yzSxW/VTsN04uoqCP6IpKXqlAz40VeWGUPJOeGthCKy/9A+NSuqS</SignatureValue><KeyInfo><o:SecurityTokenReference><o:Reference ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" URI="#uuid-eb310312-396a-4d00-8922-f77de97138cb-3"/></o:SecurityTokenReference></KeyInfo></Signature></o:Security></s:Header><s:Body u:Id="_1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><getActiveAccounts xmlns="http://service.soap.xcompany.com"><applRef>dev</applRef><resetRows>false</resetRows></getActiveAccounts></s:Body></s:Envelope>
SoapUI Request:
(somehow it won't let me past whole xml here.. )
Well, my colleague helped me figure out way to remove the extra headers from the request before it was posted to the Java SOAP service endpoint - the key was to use IClientMessageInspector and implement some logic in the BeforeSendRequest to remove the unwanted headers that were rejected by the service provider; then add a custom FormattingBehavior class to inherit from IEndpointBheavior and in the IEndPointBehavior.ApplyClientBehavior, attach the MyClientMessageInspector; finally add the customer endpoint behavior to the web service client. Here are the codes:
Where and how to remove unwanted request headers:
public class MyClientMessageInspector : IClientMessageInspector
{
public MyClientMessageInspector(ServiceEndpoint endpoint)
{
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
//Console.WriteLine(request.ToString());
var lstUnwantedStuff = new[]
{
new KeyValuePair<string, string>("Action", "http://www.w3.org/2005/08/addressing"),
new KeyValuePair<string, string>("VsDebuggerCausalityData",
"http://schemas.microsoft.com/vstudio/diagnostics/servicemodelsink")
};
foreach (var kv in lstUnwantedStuff)
{
var indexOfUnwantedHeader = request.Headers.FindHeader(kv.Key, kv.Value);
if (indexOfUnwantedHeader>=0)
{
request.Headers.RemoveAt(indexOfUnwantedHeader);
}
}
...
Where and how to use the custom ClientMessageInspector:
internal class MyFaultFormatterBehavior : IEndpointBehavior
{
...
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector(endpoint));
}
}
Where and how to attach custom EndpointBehavior:
private static void CallAccountService()
{
var client = new WSAccountv1Client(BuildCustomBinding(), GetAccountServiceEndpointAddress());
//Set client certificate
client.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.Root, X509FindType.FindByThumbprint, "xxxxxxxxxx");
//for service certificate
client.ClientCredentials.ServiceCertificate.SetDefaultCertificate(StoreLocation.LocalMachine, StoreName.TrustedPeople,
X509FindType.FindByThumbprint, "xxxxxxxxxxxxxxxxy");
client.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.PeerOrChainTrust;
//add faultformattingbehavior so we can intercept the fault reply message
client.Endpoint.EndpointBehaviors.Add(new MyFaultFormatterBehavior());
client.Open();
var header = new AuthenticationHeader()
{
application_id = applId,
password = pwd
};
var getActiveAccountsFunc = new getActiveAccounts() { applRef = "test", resetRows = true };
try
{
//MyClientMessageInspector.BeforeSendRequest is entered when this called is made
var response = client.getActiveAccounts(header, getActiveAccountsFunc);
Console.WriteLine(response.moreData);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
client.Close();
}
}
What else?
In the proxy classes, need to set the Authentication ProtectionLevel to None while on the Service level it needs to be set as ProtectionLevel.Sign:
Request level:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped = false)]
public partial class getActiveAccountsRequest
{
[System.ServiceModel.MessageHeaderAttribute(Namespace = "http://service.xcompany.com"
, ProtectionLevel = System.Net.Security.ProtectionLevel.None
)]
public AuthenticationHeader Authentication;
Service (Interface) Level:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = "http://service.xcompany.com",
ConfigurationName = "WSAccount"
, ProtectionLevel = ProtectionLevel.Sign
)]
public interface WSAccount
{

Challenges performing basic HTTP authentication on RPC SOAP client

Been trying to follow some online examples as I need to do basic authentication on a webservice client.
I generated the stub classes of the project using wsimport and tried passing the authentication credentials using javax.xml.rpc.stub class but casting the proxy class throws a java.lang.ClassCastException:
com.sun.proxy.$Proxy29 cannot be cast to javax.xml.rpc.Stub.
please can anyone review this code and point me in the right direction if am doing something wrong.
public class WebClientTester
{
public static void main(String[] args)
{
doNameEnquiry("XXXXXXXXX");
}
public static void doNameEnquiry(String acct)
{
boolean txnOk = false;
try
{
String str = "http://XXX.XXX.XXX.XXX/GwHolderService.svc?wsdl";
URL url = new URL(str.substring(0, str.indexOf("?")));
QName qname = new QName("http://tempuri.org/", "GwHolderService");
Service service = Service.create(url, qname);
SInfoHolder port = (SInfoHolder) service.getPort(SInfoHolder.class);
((javax.xml.rpc.Stub) port)._setProperty(javax.xml.rpc.Stub.USERNAME_PROPERTY, "myUser");
((javax.xml.rpc.Stub) port)._setProperty(javax.xml.rpc.Stub.PASSWORD_PROPERTY, "myPwd");
InfoHolderRequest request = new InfoHolderRequest();
request.setHolderAccountNumber(acct);
InfoHolderResponse response = port.infoHolder(request);
// System.out.println("authenticated: "+
// response.getRespMessageCode());
System.out.println("******************END RESPONSE***********");
System.out.println("responseCode: " + response.getCoderesp());
System.out.println(processResponseXML(response));
System.out.println("******************LIST DETAILS***********");
listDetails(processResponseXML(response));
}
catch (Exception ex)
{
ex.printStackTrace();
}
// return txnOk;
}
}

Categories

Resources