How to call a webservice directly from Java (without webservice library)

8

In this blog I will show you how you can call a webservice programmatically in Java without using a webservice library like JAX-WS or Apache Axis. Normally you would use of course a webservice library, but in some cases this can be useful and quick; for example when you have problems generating a client proxy with a webservice library or if you only need some small specific parts of the SOAP response XML tree. It shows that a SOAP call is just XML over HTTP, from a plain piece of Java code. Then, I will show you an example how you can use this and make your own servlet webservice-tester like a simple SoapUI in JDeveloper 11.1.1.3.

Calling a webservice programmatically without webservice library like JAX-WS or Apache Axis

In this example I make use of a simple webservice: a weather webservice available on: http://www.deeptraining.com/webservices/weather.asmx?WSDL .

The following method is an example how to create a SOAP message request and call a remote webservice using a HttpURLConnection object, receive and process the SOAP message response. It returns the weather of a specific city.

public String getWeather(String city) throws MalformedURLException,
IOException {

//Code to make a webservice HTTP request
String responseString = "";
String outputString = "";
String wsURL = "http://www.deeptraining.com/webservices/weather.asmx";
URL url = new URL(wsURL);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection)connection;
ByteArrayOutputStream bout = new ByteArrayOutputStream();
String xmlInput =
" <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://litwinconsulting.com/webservices/\">\n" +
" <soapenv:Header/>\n" +
" <soapenv:Body>\n" +
" <web:GetWeather>\n" +
" <!--Optional:-->\n" +
" <web:City>" + city + "</web:City>\n" +
" </web:GetWeather>\n" +
" </soapenv:Body>\n" +
" </soapenv:Envelope>";

byte[] buffer = new byte[xmlInput.length()];
buffer = xmlInput.getBytes();
bout.write(buffer);
byte[] b = bout.toByteArray();
String SOAPAction =
"http://litwinconsulting.com/webservices/GetWeather";
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length",
String.valueOf(b.length));
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction", SOAPAction);
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
OutputStream out = httpConn.getOutputStream();
//Write the content of the request to the outputstream of the HTTP Connection.
out.write(b);
out.close();
//Ready with sending the request.

//Read the response.
InputStreamReader isr =
new InputStreamReader(httpConn.getInputStream());
BufferedReader in = new BufferedReader(isr);

//Write the SOAP message response to a String.
while ((responseString = in.readLine()) != null) {
outputString = outputString + responseString;
}
//Parse the String output to a org.w3c.dom.Document and be able to reach every node with the org.w3c.dom API.
Document document = parseXmlFile(outputString);
NodeList nodeLst = document.getElementsByTagName("GetWeatherResult");
String weatherResult = nodeLst.item(0).getTextContent();
System.out.println("Weather: " + weatherResult);

//Write the SOAP message formatted to the console.
String formattedSOAPResponse = formatXML(outputString);
System.out.println(formattedSOAPResponse);
return weatherResult;
}

In the code above I make use of two util methods (one that makes use of a Xerces.jar library, you can download it at http://xerces.apache.org/mirrors.cgi):

//format the XML in your String
public String formatXML(String unformattedXml) {
try {
Document document = parseXmlFile(unformattedXml);
OutputFormat format = new OutputFormat(document);
format.setIndenting(true);
format.setIndent(3);
format.setOmitXMLDeclaration(true);
Writer out = new StringWriter();
XMLSerializer serializer = new XMLSerializer(out, format);
serializer.serialize(document);
return out.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

private Document parseXmlFile(String in) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(in));
return db.parse(is);
} catch (ParserConfigurationException e) {
throw new RuntimeException(e);
} catch (SAXException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}

If you put this 3 methods together in a class with a main method, than you can simply call the weather webservice. Thats all!

public class WeatherWebserviceTester {
public static void main(String[] args) {
WeatherWebserviceTester weatherWebserviceTester =
new WeatherWebserviceTester();
try {
weatherWebserviceTester.getWeather("Washington");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}

Download this class WeatherWebserviceTester.java


Create the servlet webservice tester

On our project we have a challenge where calling a webservice directly from Java is useful: because of very strict security reasons our client proxy application can access a remote webservice from only one single IP-address. This address is the machine where our production Weblogic server (WLS11g) is located and where we need to deploy our client application. This webservice is new and unfortunately it has many child-diseases: we often need to test, analyze and adjust the exact XML exchange of the SOAP-messages. See also http://technology.amis.nl/blog/12004/how-to-remove-unwanted-soap-header-elements-in-jax-ws. Testing is very problematic if you dont have a webservice tester available. Every WLS normally contains a test webservice facility – like a simple SoapUI in the server. It should be standard available at http://host:port/wls_utc. In my JDevelopers locally embedded WLS I can directly find it but not use it – my IP-address is not authorized to get information from this webservice. Unfortunately on our production WLS we cannot reach its internal WLS webservice tester. I will show you how to create a servlet webservice tester. After deploying this tester on our production WLS, we were able to test and analyze the SOAP message exchange.

The steps in JDeveloper:

  • create a new application and a new project.
  • Use the wizard to make a new Servlet, check the doGet() and the doPost() methods:

    • We will have to add HTML code to the servlet  doGet() and doPost() method to let it write two textareas, one for the SOAP message request and one for the SOAP message response. Also an input field for the webservice endpoint and a checkbox whether to format the response in XML is needed. You can first quickly make a test HTML page to create the HTML you need for this:
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Webservice tester</title>
</head>
<body>
<form action="soaprequestservlet" method="post">
<label for="wsdl">Webservice endpoint</label>
<input type="text" name="wsdl" size="120" id="wsdl"
style="font-size: 11px; color: blue;"/>
<label for="FormatXML">Format XML</label>
<input id="FormatXML" type="checkbox" name="formatXML"
value="formatXML" checked="checked"/>
<table cellspacing="0" cellpadding="0" border="0">
<tr>
<td width="45%">
<h3>SOAP Request</h3>
<textarea style="font-size: 11px; color: blue;"
name="soapmessage" cols="80" rows="40"
title="SOAP MessageRequest" id="soaprequest"></textarea>
</td>
<td width="45%">
<h3>SOAP Response</h3>
<textarea style="font-size: 11px; color: blue;"
name="soapmessageresponse" cols="80" rows="40"
title="Soap Request" id="soapresponse"></textarea>
</td>
</tr>
</table>
<input type="submit" name="Test SOAP Request"
value="Test SOAP Request"/>
</form>
</body>
</html>

When you run this page you can check the exact HTML that you want to put later into your doGet() and doPost() methods of your servlet:

  • Add the HTML code of this page to both the servlet doGet() and doPost() methods in the println() method of the PrintWriter. Then we can now add the real code that calls the webservice. The most important is the doPost() method where the webservice is called with the request SOAP message and the endpoint destination that you entered in the input fields:
public void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException,
IOException {
//Whether to format the SOAP message response or not.
String formatXML = request.getParameter("formatXML");

//Get the endpoint
if (!request.getParameter("endpoint").equals(""))
wsURL = request.getParameter("endpoint");
else
throw new ServletException("Missing endpoint location!");

//Get the SOAP message request
String xmlInput = request.getParameter("soapmessage");
requestMessage = xmlInput;

//Code to make a webservice HTTP request
URL url = new URL(wsURL);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection)connection;
String responseString = "";
String outputString = "";
//Optional: set your action
//String SOAPAction =
// "http://litwinconsulting.com/webservices/GetWeather";
ByteArrayOutputStream bout = new ByteArrayOutputStream();
OutputStream out = null;
InputStreamReader isr = null;
BufferedReader in = null;
byte[] buffer = new byte[xmlInput.length()];
buffer = xmlInput.getBytes();
bout.write(buffer);
byte[] b = bout.toByteArray();

// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length",
String.valueOf(b.length));
httpConn.setRequestProperty("Content-Type", "text/xml; charset=utf-8");

//Optional: set your action
//httpConn.setRequestProperty("SOAPAction", SOAPAction);
httpConn.setRequestMethod("POST");
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
out = httpConn.getOutputStream();

// write the content of the request to the outputstream of the HTTP Connection.
out.write(b);
out.close();
// ready with sending the request

// Read the response.
isr = new InputStreamReader(httpConn.getInputStream());
in = new BufferedReader(isr);

//Write the SOAP message response to a String.
while ((responseString = in.readLine()) != null) {
outputString =
outputString + responseString + (formatXML == null ? "\n" :
"");
}
//Format the message when the checkbox is checked.
if (formatXML != null)
outputString = format(outputString);

//write the XHTML response.
response.setContentType(CONTENT_TYPE);
PrintWriter printWriter = response.getWriter();
printWriter.println("<?xml version=\"1.0\"?>");
printWriter.println(DOC_TYPE);
printWriter.println("<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">");
printWriter.println("<head><title>Webservice tester</title></head>");
printWriter.println("<body>");
printWriter.println("<form action=\"soaprequestservlet\" method=\"post\">");
printWriter.println("<label for=\"wsdl\">Webservice endpoint</label>");
printWriter.println("<input type=\"text\" name=\"endpoint\" value=\"" +
wsURL +
"\" size=\"120\" id=\"wsdl\" style= \"; font-size: 12px; color: blue;\" />");
printWriter.println("<label for=\"FormatXML\">Format XML</label>");
printWriter.println("<input id=\"FormatXML\" type=\"checkbox\" name=\"formatXML\" value=\"formatXML\" checked=\"checked\"/>");
printWriter.println("<p/><table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">");
printWriter.println("<tr>");
printWriter.println("<td width=\"45%\">");
printWriter.println("<h3>SOAP Message Request</h3>");
printWriter.println("<textarea style= \"; font-size: 11px; color: blue\"; name=\"soapmessage\" cols=\"80\" rows=\"40\" title=\"SOAP Message Request\" id=\"soaprequest\">" +
requestMessage + "</textarea>");
printWriter.println("</td>");
printWriter.println("<td width=\"45%\">");
printWriter.println("<h3>SOAP Message Response</h3>");
printWriter.println("<textarea style= \"; font-size: 11px; color: blue\"; name=\"soapmessageresponse\" cols=\"80\" rows=\"40\"");
printWriter.println("title=\"SOAP Message Response\" id=\"soapresponse\"");

//write the SOAP message response to the textarea.
printWriter.println(outputString);

//Continue writing XHTML
printWriter.println("</textarea>");
printWriter.println("</td>");
printWriter.println("</tr>");
printWriter.println("</table>");
printWriter.println("<input type=\"submit\" name=\"Test SOAP Request\" value=\"Test SOAP Request\"/>");
printWriter.println("</form>");
printWriter.println("</body></html>");
printWriter.close();
}

In the servlet, the doGet() method is called when you call the servlet for the first time. After clicking on the button to test the SOAP request, the doPost() method is called and the SOAP message request is send to the webservice endpoint . The SOAP message response is red and written in the second textarea. Your webservice tester is ready for real use !

Download this whole servlet project SoapRequestTester.

Share.

About Author

Frank Houweling is an Oracle ADF and Java specialist with AMIS (The Netherlands). He focuses mainly on Oracle Fusion ADF, Java Enterprise development and performance management. During the past years he has been requested several times as troubleshooter of ADF projects with bad performance. As such he has been performing performance analysis, bottleneck detection and developing mitigating solutions based on these analysis. He is also the creator of the AMIS ADF Performance Monitor, an advanced monitor that can identify, report and help solve performance bottlenecks in ADF applications.

8 Comments

  1. Hi!
    In your example url address is wsURL = "http://www.deeptraining.com/webservices/weather.asmx ,it's .asmx extension, and your xmlInput =

    13
    "  <soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:web=\"http://litwinconsulting.com/webservices/\">\n" +

    14
    "   <soapenv:Header/>\n" +

    15
    "   <soapenv:Body>\n" +

    16
    "      <web:GetWeather>\n" +

    17
    "         <!--Optional:-->\n" +

    18
    "         <web:City>" + city + "</web:City>\n" +

    19
    "      </web:GetWeather>\n" +

    20
    "   </soapenv:Body>\n" +

    21
    "  </soapenv:Envelope>"

    But, if I've url address with .aspx extension,where are my methods,how I to create xmlInput?
    BR,Ana


  2. This is very close to something we are working on would it be possible to use something like this but add input boxs for the SOAP request for user testing?

  3. Frank Houweling on

    Hi Gulshan, thanks for your reply.
    In the code above I didn’t set the HTTP request property:
    //httpConn.setRequestProperty(“SOAPAction”, SOAPAction);
    But you are right, it was maybe a little confusing… I’ve adjusted it.

  4. Frank Houweling on

    Hi Ram,
    Do you get a SocketTimeoutException?
    You could try and catch (and handle) this exception .
    Regards, Frank

  5. Hi Frank ,
    Thanks for the Excellent and detailed project shared with the global user community .
    I would like to mention a draw backs with the approach  .
    The above code hangs in scenarios where the Webservice provider is un responsive. To be more specific httpConn.getInputStream() function would make the thread to hang until the input stream is totally read.
    Let me know your thoughts on how this can be handled.
    Thanks & Regards
    Ram

Leave a Reply