Reputation: 327
I'm developing an WebService JAX-WS to write log status of customers applications.
I send on every request the id, timestamp and status message. The WS only write this in database.
The service is working great, and I consume it with Delphi, making the XML requests "by hand".
So, I'm not interested in client-side of service. The client is a Delphi application and I can't change that...
I can consume this JAX-WS only one request per time. Each status update consist in a complete call to the WS.
The problem is: How can I send many status information in one single request, and specifically, how need I annotate JAX-WS to recognize multiple items in XML and give me in implementation body of function access to all elements, like an array.
I send the XML to the WS in Delphi with this code:
function JAXWS_getResponse( vXMLRequest_Envelope : WideString; vURL : String ) : WideString;
var sRequest : TStringStream;
sResponse : TStringStream;
JAXWS_Request : THTTPReqResp;
begin
sRequest := TStringStream.Create( vXMLRequest_Envelope );
sResponse := TStringStream.Create( EmptyStr );
JAXWS_Request := THTTPReqResp.Create( nil );
try
JAXWS_Request.URL := vURL;
JAXWS_Request.UseUTF8InHeader := True;
JAXWS_Request.Execute( sRequest, sResponse );
Result := sResponse.DataString;
finally
JAXWS_Request.Free;
sRequest.Free;
sResponse.Free;
end;
end;
The vXMLRequest_Envelope parameter content is like (make "by hand"):
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns2:updateStatus
xmlns:ns2="http://webVersao.microdata.com.br/">
<id_customer>123</id_customer>
<status_date>2014-08-26 15:30:05</status_date>
<status_message>WORKING</status_message>
</ns2:updateStatus>
</soapenv:Body>
</soapenv:Envelope>
So, this is the code of web service:
WebVersao_Interface.java
package br.com.microdata.webVersao;
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;
@WebService
@SOAPBinding(style = Style.RPC)
public interface WebVersao_Interface {
@WebMethod
String updateStatus(
@WebParam(name="id_customer", partName="id_customer")
String id_customer,
@WebParam(name="status_date", partName="status_date")
String status_date, // yyyy-mm-dd hh:nn:ss
@WebParam(name="status_message", partName="status_message")
String status_message
);
}
WebVersao_Implementation.java
package br.com.microdata.webVersao;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import javax.jws.WebService;
@WebService(endpointInterface = "br.com.microdata.webVersao.WebVersao_Interface")
public class WebVersao_Implementation implements WebVersao_Interface {
@Override
public String updateStatus(String id_customer, String status_date, String status_message) {
Connection conn = WebVersao_Connection.getConnection();
try {
Statement stmt = conn.createStatement();
String query =
"insert into status_log ( id_customer, status_date, status_message ) " +
String.format( "values ( %d, timestamp '%s', '%s' )",
id_customer, status_date, status_message );
stmt.execute(query);
return "DONE";
} catch (SQLException e) {
return "ERROR: " + e.getMessage();
}
}
}
So, finally, my question is:
How can I make my XML like:
<status>
<id_customer>123</id_customer>
<status_date>2014-08-26 12:30:05</status_date>
<status_message>WAITING</status_message>
</status>
<status>
<id_customer>789</id_customer>
<status_date>2014-08-26 13:43:52</status_date>
<status_message>SLEEPING</status_message>
</status>
<status>
<id_customer>123</id_customer>
<status_date>2014-08-26 15:30:05</status_date>
<status_message>WORKING</status_message>
</status>
<status>
<id_customer>456</id_customer>
<status_date>2014-08-26 18:10:08</status_date>
<status_message>SLEEPING</status_message>
</status>
and properly receive in Java like:
public String updateManyStatus( List<StatusInfo> manyStatus) { ... }
or
public String updateManyStatus( StatusInfo[] manyStatus) { ... }
or any other like-method...
public class StatusInfo {
private Long id_customer;
private String status_date;
private String status_message;
public Long getId_customer() {
return id_customer;
}
public void setId_customer(Long id_customer) {
this.id_customer = id_customer;
}
public String getStatus_date() {
return status_date;
}
public void setStatus_date(String status_date) {
this.status_date = status_date;
}
public String getStatus_message() {
return status_message;
}
public void setStatus_message(String status_message) {
this.status_message = status_message;
}
}
Thanks in advance to all StackOverflow community. You all rock!!
Upvotes: 1
Views: 1428
Reputation: 900
I guess you are almost there.
First, You need to change your SOAP Binding style on your 'WebVersao_Interface' from @SOAPBinding(style = Style.RPC)
to @SOAPBinding(style = Style.DOCUMENT)
.
RPC style has minimal support for user defined data type or complex types.
Either of these signatures in the webservice would do
public String updateManyStatus( ArrayList<StatusInfo> manyStatus) { ... }
or
public String updateManyStatus( StatusInfo[] manyStatus) { ... }
Would recommend using the array version for interoperability concerns for consuming the webservice across other non java clients.
And in the client why are you handcoding the xml message. You can instead create/populate all your StatuInfo objects; put them in an array or a list and call the appropriate webservice method instead. Let me know if that works.
Upvotes: 1
Reputation: 327
Here is how I solved my own question.
Far far away from an elegant solution, but I need one, and this solves my problem.
Please, anybody who know some how of do it in a better way, please comment.
I don't like this approach, but I don't know how do it better!
Well, there is my solution:
I just mask my XML with many items in a single WideString parameter <xml_content>
, and then in Java, unmask, parse as normal XML and fill an array.
My XML request is:
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<ns2:updateStatusMulti
xmlns:ns2="http://webVersao.microdata.com.br/">
<xml_content>
{?xml version="1.0" encoding="utf-8"?}
{many_status}
{status}
{id_customer}123{/id_customer}
{status_date}2014-08-26 12:30:05{/status_date}
{status_message}WAITING{/status_message}
{/status}
{status}
{id_customer}789{/id_customer}
{status_date}2014-08-26 13:43:52{/status_date}
{status_message}SLEEPING{/status_message}
{/status}
{status}
{id_customer}123{/id_customer}
{status_date}2014-08-26 15:30:05{/status_date}
{status_message}WORKING{/status_message}
{/status}
{status}
{id_customer}456{/id_customer}
{status_date}2014-08-26 18:10:08{/status_date}
{status_message}SLEEPING{/status_message}
{/status}
{/many_status}
</xml_content>
</ns2:updateStatusMulti>
</soapenv:Body>
</soapenv:Envelope>
then I added this function in webservice inteface:
@WebMethod
String updateStatusMulti(
@WebParam(name="xml_content", partName="xml_content")
String xml_content);
and in the implementation, I fill the array and call the function updateManyStatus
in my way, as I want!
@Override
public String updateStatusMulti( String xml_content ) {
try{
//"unmask" then xml
xml_content = xml_content.replace('{', '<');
xml_content = xml_content.replace('}', '>');
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new InputSource(new ByteArrayInputStream(xml_content.getBytes("utf-8"))));
//optional, but recommended
//read this - http://stackoverflow.com/questions/13786607/normalization-in-dom-parsing-with-java-how-does-it-work
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("status");
int nCount = nList.getLength();
StatusInfo[] manyStatus = new StatusInfo[nCount];
for (int index = 0; index < nCount; index++) {
Node nNode = nList.item(index);
//("\nCurrent Element :" + nNode.getNodeName());
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
String id_customer = eElement.getElementsByTagName("id_customer").item(0).getTextContent();
String status_date = eElement.getElementsByTagName("status_date").item(0).getTextContent();
String status_message = eElement.getElementsByTagName("status_message").item(0).getTextContent();
manyStatus[index].setId_customer( Long.valueOf(id_customer) );
manyStatus[index].setStatus_date( status_date );
manyStatus[index].setStatus_message( status_message );
}
}
//return String.format( "DONE: ( %d )", nCount );
//here is my wanted call
return updateManyStatus( manyStatus );
} catch (Exception e) {
return "ERROR: " + e.getMessage(); //xml_content;
}
}
Anyway, thanks for everybody!!!
StackOverflow rocks!
Upvotes: 0