Go to content Go to sidebar

Browsing the "Java" category...

More on the Ant PropertyFile task

A reader writes in, requesting greater control over the behavior of the entry element of the ant PropertyFile Task:

I am having a problem where in, if the number in test.properties is more than 999 then the increment adds a comma. The incremented number after 999 will be 1,000.

The answer is to use the pattern attribute of the entry element:


<project default="run">
  <target name="run">
    <propertyfile file="test.properties">
      <entry key="count" type="int" operation="+" value="1" pattern="0">
    </propertyfile>
  </target>
</project>

With the addition of this attribute, the count property no longer includes the thousands separator:

$ cat test.properties
#Sat Apr 18 20:16:30 GMT 2009
count=999
$ ant
Buildfile: build.xml

run: [propertyfile] Updating property file: test.properties

BUILD SUCCESSFUL Total time: 0 seconds $ cat test.properties #Sat Apr 18 20:29:41 GMT 2009 count=1000

Building an executable jar with Ant

An executable jar file has a defined default class, allowing the default class to be invoked without explicitly identifying it via the command line. On a supporting OS (such as Mac OS/X or Microsoft Windows), this allows the class to be invoked by double-clicking the file.

I know that making a jar file executable requires an entry in the manifest file. I can usually remember that the attribute in question is Main-Class (although I'm usually fuzzy about the proper capitalization). The problem is remembering the correct command line options to insert my own MANIFEST.MF file into a jar file.

All in all, it is much simpler to just use ant to handle it for me. Let's start with the example from my Ant Hello World Revisited. The new ant build file follows, with the new lines shown in bold. Note that I've also designated the "jar" task as the default task.


$ cat hello.xml
<project default="jar">
  <target name="compile">
    <javac srcdir="." />
  </target>
  <target name="jar" depends="compile">
    <jar destfile="hello.jar"
         basedir="."
         includes="**/*.class">
      <manifest>
        <attribute name="Main-Class" value="hello" />
      </manifest>
    </jar>
  </target>
</project>
$ cat hello.java public class hello { public static void main( String[] args ) { System.out.println( "Hello World" ); } }

Now we simply build our jar file:


$ rm *.jar
$ ant -f hello.xml
Buildfile: hello.xml

compile:

jar: [jar] Building jar: /Tutorial/Ant/Jar/hello.jar

BUILD SUCCESSFUL Total time: 2 seconds

And execute the default class by using the -jar command line option to java:


$ java -jar hello.jar
Hello World

Disclaimer: I don't claim to be an expert on ant. Please send comments and corrections.


Java Web Service Messages Client Redux

What's the simplest thing that …

I'm sure that my colleagues are tired of me asking "What's the simplest thing …". But simple things are focused on just one thing. And when the simple thing fails, then there is just one thing to check. In furtherance of the "simplest thing", here is an updated Java Web Services Message Client pointed at a publicly available web service. Thanks to Sean Collins of XML Me for allowing us to use their web service.

This client reads an input document from standard input, invokes a web service, and then prints the web service response. It has been updated to support the SOAPActionURI required by the Shakespeare web service and to force a newline between XML elements (changes are shown in bold). The results shown here use Java 1.4.2_11 and Axis 1.3.


import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.constants.Style;
import org.apache.axis.Message;
import org.apache.axis.message.SOAPEnvelope;


public class Invoke {

    public static void main ( String[] args )
        throws Exception
    {
        String endpoint   = "http://www.xmlme.com/WSShakespeare.asmx";
        String action     = "http://xmlme.com/WebServices/GetSpeech";
        /*
         * Two optional command line arguments:
         *   the web service uri
         *   the web action uri
         */
        switch(args.length) {
        case 0:
            break;
        case 1:
            endpoint = args[0];
            action   = null;
            break;
        case 2:
            endpoint = args[0];
            action   = args[1];
            break;
        default:
            System.out.println( "Usage java -cp $AXISCLASSPATH Invoke [WebServiceUri] [WebActionUri] < data.xml" );
            System.exit(2);
        }
        /*
         * Read input
         */
        String document = streamToString( System.in );
        System.out.println( document );
        System.out.println( "Invoking " + endpoint + "\n" );
        /*
         * Pass to web service
         */
        Service service = new Service();
        Call call       = (Call) service.createCall();
        call.setTargetEndpointAddress( new java.net.URL(endpoint) );
        call.setOperationStyle( org.apache.axis.constants.Style.MESSAGE );
        if ( action != null ) {
            call.setProperty(Call.SOAPACTION_USE_PROPERTY,Boolean.TRUE);
            call.setProperty(Call.SOAPACTION_URI_PROPERTY,action);
        }
        SOAPEnvelope envelope = call.invoke( new Message(document) );
        /*
         * Print the Web Service return
         */
        System.out.println( envelope.getBody().toString().replaceAll("><",">\n<") );
    }

    /**
     * Utility to read textual data from in InputStream to a String
     */
    public static String streamToString( java.io.InputStream is )
        throws java.io.IOException
    {
        java.io.InputStreamReader ir = new java.io.InputStreamReader(is);
        java.io.BufferedReader    in = new java.io.BufferedReader(ir);

        StringBuffer buffer = new StringBuffer();
        {
            String line = null;
            while( (line=in.readLine()) != null ) {
                buffer.append( line );
                buffer.append( '\n' );
            }
        }
        return buffer.toString();
    }
}

And here is the client in action. For brevity, I've requested a Shakespeare speech containing those famous words "Hello, World". You may want to request something more along the lines of: "dogs of war" or "unto the breach".

12 $ javac -classpath $AXISCLASSPATH Invoke.java
13 $ java -classpath $AXISCLASSPATH Invoke < data/speech.xml
<?xml version="1.0" standalone="yes" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:ns="http://xmlme.com/WebServices">
  <soap:Body>
    <ns:GetSpeech>
      <ns:Request>Hello, World</ns:Request>
    </ns:GetSpeech>
  </soap:Body>
</soap:Envelope>

Invoking http://www.xmlme.com/WSShakespeare.asmx

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<GetSpeechResponse xmlns="http://xmlme.com/WebServices">
<GetSpeechResult>&lt;MESSAGE&gt;Speech not found.&lt;/MESSAGE&gt;</GetSpeechResult>
</GetSpeechResponse>
</soapenv:Body>
14 $

Feb 9 08: Examing your Java app with a debugging proxy.


Open Source JMS Providers

I’d like to take a look at JMS and the leading contenders for an open source JMS provider seem to be:

Circumstances are pushing me to JORAM by a process of elimination:

  • ActiveMQ seems to be happiest with Java 1.5
  • The last release of OpenJMS seems to have been back in June 2006
  • JBoss Messaging appears to only run inside of JBoss

I’ll let you know how things work out.


Examining your Java App with a Debugging Proxy

Unless you're one of those annoying people who never makes a mistake, the time will come when your java web application is choking on it's web messages and you just don't know why. When that time comes, one of things that you will really want to see are the raw messages going back and forth. Which may be a bit problematic if your tools have been hiding the raw messages from you.

When I find myself there, I like to set up a debugging proxy (an explicit proxy will also work). This is as easy as specifying a couple of system properties (http.proxyHost and http.proxyPort) on the command line. Here I show my Java web services message client using Fiddler as a debugging proxy.

1 $ java -classpath $AXISCLASSPATH -Dhttp.proxyHost=localhost -Dhttp.proxyPort=8888 Simple < data/echo.xml
<?xml version="1.0" standalone="yes" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:ns1="http://soapinterop.org/xsd">
  <soap:Body>
    <ns1:echoString>
      <ns1:echoStringRequest>Hello World</ns1:echoStringRequest>
    </ns1:echoString>
  </soap:Body>
</soap:Envelope>

Invoking http://stephan-desktop/axis/services/echo

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <ns2:echoStringResponse
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:ns2="http://soapinterop.org/xsd">
    <return
        xsi:type="xsd:string"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Hello World</return>
  </ns2:echoStringResponse>
</soapenv:Body>

Producing the following view in Fiddler.

Fiddler Capture of a Java web services invocation

By selecting the "View in Notepad" button, we can see the complete response from the web service (formatted below for readability):

<?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:Header>
  <ns1:echoMeStringResponse
      soapenv:actor="http://schemas.xmlsoap.org/soap/actor/next"
      soapenv:mustUnderstand="0"
      xsi:type="soapenc:string"
      xmlns:ns1="http://soapinterop.org/echoheader/"
      xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">header text</ns1:echoMeStringResponse>
  </soapenv:Header>
  <soapenv:Body>
    <ns2:echoStringResponse
        soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
        xmlns:ns2="http://soapinterop.org/xsd">
      <return xsi:type="xsd:string">Hello World</return>
    </ns2:echoStringResponse>
  </soapenv:Body>
</soapenv:Envelope>

Apache Tcpmon

I was familiar with tcpmon from Apache Axis distribution. But I had no idea that there was a independent Apache TCPMon. The primary difference between the two seems to be the built in sender screen that allows you to enter a SOAP request, submit the request to a web service, and view the response.

If you work with web services in Java, then it is definitely worth the download. The screen shot below shows the same web service request and response used in my Java Web Services Message Client – the request on top and the response below.

Tcpmon showing Web Service request and Response


Java Web Services Message Client

Updated Java Web Services Message Client Redux now available.

Most of the Java web services examples on the web use an RPC-style interface. That's fine when you're calling a web service implemented in Java. But web services being what they are, you'll eventually find yourself invoking a message-style web service whose WSDL gives wsdl2java fits.

When that time comes, you can either roll your own code rather than use wsdl2java or you can go with the flow with a message-style interface. I think that you'll find it easier to go with the message-style interface. And to make it even easier, here is a simple message-style client to get you started.

This client reads an input document from standard input, invokes a web service, and then prints the web service response. The results shown here use Java 1.4.2_11 and Axis 1.3.


import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.constants.Style;
import org.apache.axis.Message;
import org.apache.axis.message.SOAPEnvelope;


public class Simple {

    public static void main ( String[] args )
        throws Exception
    {
        String endpoint   = "http://stephan-desktop/axis/services/echo";
        /*
         * If there is a command line argument,
         * then use it as the web service endpoint
         */
        if ( args.length > 0 ) {
            endpoint = args[0];
        }
        /*
         * Read input
         */
        String document = streamToString( System.in );
        System.out.println( document );
        System.out.println( "Invoking " + endpoint + "\n" );
        /*
         * Pass to web service
         */
        Service service = new Service();
        Call call       = (Call) service.createCall();
        call.setTargetEndpointAddress( new java.net.URL(endpoint) );
        call.setOperationStyle( org.apache.axis.constants.Style.MESSAGE );
        SOAPEnvelope envelope = call.invoke( new Message(document) );
        /*
         * Print the Web Service return
         */
        System.out.println( envelope.getBody().toString() );
    }

    /**
     * Utility to read textual data from in InputStream to a String
     */
    public static String streamToString( java.io.InputStream is )
        throws java.io.IOException
    {
        java.io.InputStreamReader ir = new java.io.InputStreamReader(is);
        java.io.BufferedReader    in = new java.io.BufferedReader(ir);

        StringBuffer buffer = new StringBuffer();
        {
            String line = null;
            while( (line=in.readLine()) != null ) {
                buffer.append( line );
                buffer.append( '\n' );
            }
        }
        return buffer.toString();
    }
}

And here is the client in action, calling the echoString operation of the echo web service example included in the Axis distribution. The actual response body is a single line, I have taken the liberty of formatting the response for easier reading.

12 $ javac -classpath $AXISCLASSPATH Simple.java
13 $ java -classpath $AXISCLASSPATH Simple < data/echo.xml
<?xml version="1.0" standalone="yes" ?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:ns1="http://soapinterop.org/xsd">
  <soap:Body>
    <ns1:echoString>
      <ns1:echoStringRequest>Hello World</ns1:echoStringRequest>
    </ns1:echoString>
  </soap:Body>
</soap:Envelope>

Invoking http://stephan-desktop/axis/services/echo

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <ns2:echoStringResponse
      soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
      xmlns:ns2="http://soapinterop.org/xsd">
    <return
        xsi:type="xsd:string"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">Hello World</return>
  </ns2:echoStringResponse>
</soapenv:Body>
14 $

Feb 9: Examing your Java app with a debugging proxy.

Sep 19: Java Web Services Message Client Redux.


« Previous