Wednesday, January 13, 2010

My mistake

Today a strange thing happened while I was working on our company project. We use Sun webserver to deploy our java application.

We were testing our application as its that scary testing phase. (I say scary because, we have a points system where our points are directly related to the number of bugs found while testing.)

And on such a day, our application which till afternoon was working fine, suddenly stopped working. It could not connect to the database!

I checked everything, the code, the connection pool classes, the web server configuration, the data source settings and configuration and even the database.
I and my team broke our heads to resolve the issue. But all was going in vain.

Then after an hour and half, I finally decided to blame it on the database and told the same to the DBA. For which he ofcourse disagreed.

Then the matter was escalated and our development head for help. By looking the at logs he that the .dtd is missing.
Well, there were only 2 xml files, one is web.xml and other is sun-web.xml (sun-web.xml is specific to Sun wevserver). Both were pointing to a internet site of Sun (Example : http://www.sun.com/software/dtd/appserver/sun-web-app_2_5-0.dtd).

I decided to check them on the browser and to my surprise, I found that the Sun's server which hosts these .dtd files has gone down.

Phew, finally found the issue , We then downloaded the .dtd file from some other place and placed it in the config folder of the sun webserver.
All was fine then, the application started working fine.

But due to this lack of knowledge, we wasted about 2 hours, which can be crucial.

So the moral of the story is that any server can go down, so always make sure you place the .dtd or .xsd file which you are referring in your xml on your local server.

Tuesday, January 12, 2010

Avoid namespace in Axis2

To avoid a namespace in the web service request in Axis2, you can use the following trick.

This will not work if you want to deploy multiple services or endpoints within the same code (services.xml).
But if you have one service and the services.xml of Axis2 is dedicated for it, then you can achieve the option of not sending /setting the namespace from the client.

For this, simply remove the serviceGroup tag from services.xml and keep only one service in the services.xml file.

Example : If your services.xml file is
<?xml version="1.0" encoding="UTF-8"?>
<serviceGroup>
<service name="MainService" scope="application">
<description>
MainService Service
</description>
<operation name="processSOAPRequest">
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<parameter name="ServiceClass">com.darel.server.service.MainService</parameter>
</service>
</serviceGroup>

Change it by removing the <serviceGroup> and put the service as the main element.
<?xml version="1.0" encoding="UTF-8"?>
<service name="MainService" scope="application">
<description>
MainService Service
</description>
<operation name="processSOAPRequest">
<messageReceiver class="org.apache.axis2.receivers.RawXMLINOutMessageReceiver"/>
</operation>
<parameter name="ServiceClass">com.darel.server.service.MainService</parameter>
</service>

Since there is only one service, Axis2 does not make the namespace mandatory in the Soap request.

Soap Client with XML DOM

Below is a sample soap client, which can take in a XML DOM, which is got from a xml string.

String targetERP = "http://myserver.com/NewWebService/services/ServiceName";

SOAPConnectionFactory scf = SOAPConnectionFactory.newInstance();
connection = (SOAPConnection)scf.createConnection();

// SOAPFactory sf = SOAPFactory.newInstance();

// Create the message
MessageFactory mf = MessageFactory.newInstance();
SOAPMessage message = mf.createMessage();

SOAPPart soapPart = ((SOAPMessage) message).getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
// message body
SOAPBody body = envelope.getBody();

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();

//strRequestXML is a XML string which may be generated by java.
ByteArrayInputStream x = new ByteArrayInputStream(strRequestXML.getBytes());
Document doc = db.parse(x);
body.addDocument(doc); // add the xml to the soap messahe body

((SOAPMessage) message).writeTo(System.out);
System.out.println("\n");
URL endpoint = new URL(targetERP);

SOAPMessage response = connection.call(message, endpoint);
// SOAPMessage response = connection.call("",
// endpoint);
connection.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
response.writeTo(baos);
responseStr = baos.toString();

Of course the imports are
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import javax.xml.soap.*;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;

Monday, January 4, 2010

String builder using variable args

In many cases, we may have to append large number of strings to get a complete string which is desired by the program. One example can be the SQL string where you are appending the values to a sql string in java.

When it comes to appending large amount of strings, it better to use StringBuffer or StringBuilder (StringBuilder is faster since its not synchronized).
Appending to StringBuilder using .append can increase the amount of code and if done in single line can look ugly.

To avoid this, you can use the below method which does it in a clean way by calling a method and passing all string objects as variables.

/**
* Given a continuous string variables, it appends them using a string builder and returns a string.
*
* @param strings - Variable args, a unlimited variables of type String
* @return - A string which is built from the given string variables.
*/
public static String buildString(String... strings) {

    StringBuilder sb = new StringBuilder();

    for (String str : strings) {
        sb.append(str);
    }
    return sb.toString();
}

//Some method to call the above method by passing variable args
public void someMethod () {
    String str = buildString("This", " is", " a", " long string", " which will", " be ", " appended", " to demonstrate", " variable", " args", " feature");
}