How to return XML from web service - java

This may be one of the insane / stupid / dumb / lengthy questions as I am newbie to web services.
I want to write a web service which will return answer in XML format (I am using my service for YUI autocomplete). I am using Eclipse and Axis2 and following http://www.softwareagility.gr/index.php?q=node/21
I want response in following format
<codes>
<code value="Pegfilgrastim"/>
<code value="Peggs"/>
<code value="Peggy"/>
<code value="Peginterferon alfa-2 b"/>
<code value="Pegram"/>
</codes>
Number of code elements may vary depending on response.
Till now I tried following ways
1) Create XML using String buffer and return the string.(I am providing partial code to avoid confusion)
public String myService ()
{
// Some other stuff
StringBuffer outputXML = new StringBuffer();
outputXML.append("<?xml version='1.0' standalone='yes'?>");
outputXML.append("<codes>");
while(SOME_CONDITION)
{
// Some business logic
outputXML.append("<code value=\""+tempStr+"\">"+"</code>");
}
outputXML.append("</codes>");
return (outputXML.toString());
}
It gives following response with unwanted <ns:myServiceResponse> and <ns:return> element.
<ns:myServiceResponse>
<ns:return>
<?xml version='1.0' standalone='yes'?><codes><code value="Peg-shaped teeth"></code><code value="Pegaspargase"></code><code value="Pegfilgrastim"></code><code value="Peggs"></code><code value="Peggy"></code><code value="Peginterferon alfa-2 b"></code><code value="Pegram"></code></codes>
</ns:return>
</ns:findTermsResponse>
But it didnt work with YUI autocomplete (May be because it required response in format mentioned above)
2) Using DocumentBuilderFactory :
Like
public Element myService ()
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element codes = doc.createElement("codes");
while(SOME_CONDITION)
{
// Some business logic
Element code = doc.createElement("code");
code.setAttribute("value", tempStr);
codes.appendChild(code);
}
return(codes);
}
Got following error
org.apache.axis2.AxisFault: Mapping qname not fond for the package: com.sun.org.apache.xerces.internal.dom
3) Using servlet : I tried to get same response using simple servlet and it worked. Here is my servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
StringBuffer outputXML = new StringBuffer();
response.setContentType("text/xml");
PrintWriter out = response.getWriter();
outputXML.append("<?xml version='1.0' standalone='yes'?>");
outputXML.append("<codes>");
while(SOME_CONDITION)
{
// Some business logic
outputXML.append("<code value=\"" + tempStr + "\">" + "</code>");
}
outputXML.append("</codes>");
out.println(outputXML.toString());
}
It gave response same as mentioned above and it worked with YUI autocomplete without any extra tag.
Please can you tell how can I get XML response without any unwanted elements ?
Thanks.

Axis2 is for delivering Objects back to the caller. Thats why it adds extra stuff to the response even it is a simple String object.
Using the second approach your service returns a complex Java object (Element instance) that is for describing an XML fragment. This way the caller has to be aware of this object to be able to deserialize it and restore the Java object that contains XML data.
The third approach is the simplest and best in your case regarding the return type: it doesn't return a serialized Java object, only the plain xml text. Of course you could use DocumentBuilder to prepare the XML, but in the end you have to make String of it by calling the appropriate getXml(), asXml() method (or kind of...)

Finally got it work though I am not able to remove unwanted element. (I don't bother till all things are in place). I used AXIOM to generate response.
public OMElement myService ()
{
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("", "");
OMElement codes = fac.createOMElement("codes", omNs);
while(SOME_CONDITION)
{
OMElement code = fac.createOMElement("code", null, codes);
OMAttribute value = fac.createOMAttribute("value", null, tempStr);
code.addAttribute(value);
}
return(codes);
}
Links : 1) http://songcuulong.com/public/html/webservice/create_ws.html
2) http://sv.tomicom.ac.jp/~koba/axis2-1.3/docs/xdocs/1_3/rest-ws.html

I think you cannot return your custom xml with Axis. It will wrap it into its envelope anyways.

Related

chunking soap web service using axis2 in java?

I am implementing invoking of a soap web service in java
I have a wsdl file that I have imported using the embedded wsdl2java in axis2
then I was able to call the web service and it is working fine
util the size of the request exceed a 30 mega in size
the output request consist of the following parameters:
<param1>some value</param1>
<array>
recored1
recored2
.
.
.
</array>
I was able to send 500000 recodes but when exceed this number I stuck in getting "java heap space error"
question is is there any way to send the soap request in small chunks ...and does importing the WSDL using xmlbeans affect the performance
for rest APIs I was able to add transfer encoding for chunk and provide the body of it in small chunks but for soap services I found no solutions, please if there is any example of that I will be grateful.. thanks in advance
Streaming one transaction require all pipeline involved steps are in a streaming fashion. If one of them collapse the stream (i.e. myStream.collect(toList())) then, the streaming process will be broken and, at that point, all the input stream will be into memory (maybe filtered, reducted, ...).
In general, to process a XML input in a streaming fashion (under axis2) you could use Axiom, a simple example to process in streaming is (from here):
public void processFragments(InputStream in) throws XMLStreamException {
// Create an XMLStreamReader without building the object model
XMLStreamReader reader =
OMXMLBuilderFactory.createOMBuilder(in).getDocument().getXMLStreamReader(false);
while (reader.hasNext()) {
if (reader.getEventType() == XMLStreamReader.START_ELEMENT &&
reader.getName().equals(new QName("tag"))) {
// A matching START_ELEMENT event was found. Build a corresponding OMElement.
OMElement element =
OMXMLBuilderFactory.createStAXOMBuilder(reader).getDocumentElement();
// Make sure that all events belonging to the element are consumed so
// that the XMLStreamReader points to a well defined location (namely the
// event immediately following the END_ELEMENT event).
element.build();
// Now process the element.
processFragment(element);
} else {
reader.next();
}
}
}
Although you can open a HTTP stream and use this snippet, unfortunately translate it to your autogenerated client is not easy.
Create an AXIOM client is much less comfortable since you must to deal with AXIOM objects, from the documentation:
private static EndpointReference targetEPR =
new EndpointReference("http://localhost:8080/axis2/services/StockQuoteService");
public static OMElement getPricePayload(String symbol) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("http://axiom.service.quickstart.samples/xsd", "tns");
OMElement method = fac.createOMElement("getPrice", omNs);
OMElement value = fac.createOMElement("symbol", omNs);
value.addChild(fac.createOMText(value, symbol));
method.addChild(value);
return method;
}
public static OMElement updatePayload(String symbol, double price) {
OMFactory fac = OMAbstractFactory.getOMFactory();
OMNamespace omNs = fac.createOMNamespace("http://axiom.service.quickstart.samples/xsd", "tns");
OMElement method = fac.createOMElement("update", omNs);
OMElement value1 = fac.createOMElement("symbol", omNs);
value1.addChild(fac.createOMText(value1, symbol));
method.addChild(value1);
OMElement value2 = fac.createOMElement("price", omNs);
value2.addChild(fac.createOMText(value2,
Double.toString(price)));
method.addChild(value2);
return method;
}
public static void main(String[] args) {
try {
OMElement getPricePayload = getPricePayload("WSO");
OMElement updatePayload = updatePayload("WSO", 123.42);
Options options = new Options();
options.setTo(targetEPR);
options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
ServiceClient sender = new ServiceClient();
sender.setOptions(options);
sender.fireAndForget(updatePayload);
System.err.println("price updated");
OMElement result = sender.sendReceive(getPricePayload);
String response = result.getFirstElement().getText();
System.err.println("Current price of WSO: " + response);
} catch (Exception e) {
e.printStackTrace();
}
}
then you can digest the response in a streaming fashion way:
result.getFirstElement().getText()
if your WSDL definition is complex may be suitable write an AXIOM client only for big transactions but if you can split the call will be a much better approach.

How to get individual attribute from the XML file in a simpler way

I am trying to send XML file to one of my Servlet class and I am able to do that. Below is my XML file-
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<request id="a487bd863c3e4513a7893966f8e186f1">
<app hash="sha1"/>
</request>
And following is my Servlet doPost method in which I need to parse the XML file and get id and hash value from that XML file.
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String line;
BufferedReader br = new BufferedReader(request.getReader());
while ((line = br.readLine()) != null) {
System.out.println(line);
// now here parse the line and get `id and hash value`
// from it.
}
}
I am thinking what is the best way to get id and hash value from that XML file. I know one way is to parse the XML file and get the id and hash value. Is there any easy or direct way to get what I am looking for?
Any simple example will be appreciated.
try XPath
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
String id = xPath.evaluate("/request/#id",
new InputSource(request.getInputStream()));
If you need both id and hash then
InputStream is = request.getInputStream();
Document doc = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(is);
String id = ((Element) doc.getElementsByTagName("request").item(0))
.getAttribute("id");
String hash = ((Element) doc.getElementsByTagName("app").item(0))
.getAttribute("hash");
since parsers close InpuStream we need to prevent it
InputStream is = new BufferedInputStream(request.getInputStream()) {
public void close() {
}
};
You can use sax parser or dom parser to parse xml file.

XML parsing java confirmation

this is the way i made an XML file to a Java object(s).
i used "xjc" and a valid XML schema, and i got back some "generated" *.java files.
i imported them into a different package in eclipse.
I am reading the XML file in 2 way now.
1) Loading the XML file:
System.out.println("Using FILE approach:");
File f = new File ("C:\\test_XML_files\\complex.apx");
JAXBElement felement = (JAXBElement) u.unmarshal(f);
MyObject fmainMyObject = (MyObject) felement.getValue ();
2) Using a DOM buider:
System.out.println("Using DOM BUILDER Approach:");
JAXBElement element = (JAXBElement) u.unmarshal(test());;
MyObject mainMyObject = (MyObject ) element.getValue ();
now in method "test()" the code below is included:
public static Node test(){
Document document = parseXmlDom();
return document.getFirstChild();
}
private static Document parseXmlDom() {
Document document = null;
try {
// getting the default implementation of DOM builder
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
// parsing the XML file
document = builder.parse(new File("C:\\test_XML_files\\MyXML_FILE.apx"));
} catch (Exception e) {
// catching all exceptions
System.out.println();
System.out.println(e.toString());
}
return document;
}
is this the standard way of doing XML to an Java Object?
I tested if I could access the object and everything works fine. (so far)
Do you suggest a different approach?? or is this one sufficient?
I don't know about a "standard way", but either way looks OK to me. The first way looks simpler ( less code ) so that's the way I'd probably do it, unless there were other factors / requirements.
FWIW, I'd expect that the unmarshal(File) method was implemented to do pretty much what you are doing in your second approach.
However, it is really up to you (and your co-workers) to make judgments about what is "sufficient" for your project.

Deserialization with Axis 2

I have some Java code that takes an XML (SOAP) message and returns the deserialized object:
public static <T> T deserializeObject(String xml, Class<T> clazz) throws AxisFault, Exception {
assert xml != null : "xml != null";
assert clazz != null : "clazz != null";
T result = null;
try {
Message message = new Message(SOAP_START + xml + SOAP_END);
result = (T)message.getSOAPEnvelope().getFirstBody().getObjectValue(clazz);
} catch (Exception e) {
// most likely namespace error due to removed namespaces
Message message = new Message(SOAP_START_XSI + xml + SOAP_END);
result = (T)message.getSOAPEnvelope().getFirstBody().getObjectValue(clazz);
}
return result;
}
However this code only works with Axis 1.4 :-( Could someone Help me have that code work with Axis 2?
In fact, I might just need to know what to replace the import org.apache.axis.Message with?
Thanks in advance.
Every message within the Axis2 engine is wrapped inside a MessageContext object. When a SOAP message arrives into the system or is prepared to be sent out, we create an AXIOM object model of the SOAP message.
(Please read the AXIOM article series for more information on AXIOM). This AXIOM model is then included inside the message context object. Let's see how to access this SOAP message inside Axis2.
// if you are within a handler, reference to the message context
MessageContext messageContext;
object will be passed to you through Handler.invoke(MessageContext) method.
SOAPEnvelope soapEnvelope = messageContext.getEnvelope();
please see :
javax.xml.soap
Interface SOAPEnvelope
Processing Axis2 message

Tagsoup fails to parse html document from a StringReader ( java )

I have this function:
private Node getDOM(String str) throws SearchEngineException {
DOMResult result = new DOMResult();
try {
XMLReader reader = new Parser();
reader.setFeature(Parser.namespacesFeature, false);
reader.setFeature(Parser.namespacePrefixesFeature, false);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new SAXSource(reader,new InputSource(new StringReader(str))), result);
} catch (Exception ex) {
throw new SearchEngineException("NukatSearchEngine.getDom: " + ex.getMessage());
}
return result.getNode();
}
It takes a String that contains the html document sent by the http server after a POST request, but fails to parse it properly - I only get like four nodes from the entire document. The string itself looks fine - if I print it out and copypasta it into a text document I see the page I expected.
When I use an overloaded version of the above method:
private Node getDOM(URL url) throws SearchEngineException {
DOMResult result = new DOMResult();
try {
XMLReader reader = new Parser();
reader.setFeature(Parser.namespacesFeature, false);
reader.setFeature(Parser.namespacePrefixesFeature, false);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new SAXSource(reader, new InputSource(url.openStream())), result);
} catch (Exception ex) {
throw new SearchEngineException("NukatSearchEngine.getDom: " + ex.getMessage());
}
return result.getNode();
}
then everything works just fine - I get a proper DOM tree, but I need to somehow retrieve the POST answer from server.
Storing the string in a file and reading it back does not work - still getting the same results.
What could be the problem?
Is it maybe a problem with the xml encoding?
This seems like an encoding problem. In the code example of yours that doesn't work you're passing the url as a string into the constructor, which uses it as the systemId, and you get problems with Tagsoup parsing the html. In the example that works you're passing the stream in to the InputSource constructor. The difference is that when you pass in the stream then the SAX implementation can figure out the encoding from the stream.
If you want to test this you could try these steps:
Stream the html you're parsing through a java.io.InputStreamReader and call getEncoding on it to see what encoding it detects.
In your first example code, call setEncoding on the InputSource passing in the encoding that the inputStreamReader reported.
See if the first example, changed to explicitly set the encoding, parses the html correctly.
There's a discussion of this toward the end of an article on using the SAX InputSource.
To get a POST response you first need to do a POST request, new InputSource(url.openStream()) probably opens a connection and reads the response from a GET request. Check out Sending a POST Request Using a URL.
Other possibilities that might be interesting to check out for doing POST requests and getting the response:
Jersey Web Client
HtmlUnit

Categories

Resources