Browsing the "Java" category...
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.

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.

Java Web Services Message Client
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.
Modifying Property Files with Ant
I was recently testing a Web Service that expected a unique key be passed with each invocation. I could have used the date/time or I could have persisted a counter in a database. Instead, I used the optional ant propertyfile task to persist a counter in a property file.
Here is a simple ant build file demonstrating how to increment a counter in a Java properties file. The propertyfile file attribute specifies the name of the property file and each nested entry element specifies how the value of a property file key should be modified. In this case, the value of the key "count" is treated as an int and the value 1 is added upon each invocation.
<project default="run">
<target name="run">
<propertyfile file="test.properties">
<entry key="count" type="int" operation="+" value="1" />
</propertyfile>
</target>
</project>
Here is the build file in operation.
1 $ cat test.properties
count=100
2 $ ant run
Buildfile: build.xml
run:
[propertyfile] Updating property file: /Projects/Learn/Ant/propertyfile/test.properties
BUILD SUCCESSFUL
Total time: 0 seconds
3 $ cat test.properties
#Sun Oct 01 14:11:06 EDT 2006
count=101
The propertyfile entry element also allows us to specify a default value.
<project default="run">
<target name="run">
<propertyfile file="test.properties">
<entry key="count" default="10" type="int" operation="+" value="1" />
</propertyfile>
</target>
</project>
1 $ rm test.properties
2 $ ant run
Buildfile: build.xml
run:
[propertyfile] Creating new property file: /Projects/Learn/Ant/propertyfile/test.properties
BUILD SUCCESSFUL
Total time: 0 seconds
3 $ cat test.properties
#Sun Oct 01 14:30:18 EDT 2006
count=11
4 $ ant run
Buildfile: build.xml
run:
[propertyfile] Updating property file: /Projects/Learn/Ant/propertyfile/test.properties
BUILD SUCCESSFUL
Total time: 0 seconds
5 $ cat test.properties
#Sun Oct 01 14:37:12 EDT 2006
count=12
And finally, another test to show that any keys not explicitly specified are left alone.
1 $ cat test.properties
#Sun Oct 01 14:37:12 EDT 2006
count=12
more=another value
andmore=yet another value
2 $ ant run
Buildfile: build.xml
run:
[propertyfile] Updating property file: /Projects/Learn/Ant/propertyfile/test.properties
BUILD SUCCESSFUL
Total time: 0 seconds
3 $ cat test.properties
#Sun Oct 01 14:47:09 EDT 2006
andmore=yet another value
more=another value
count=13
Disclaimer: I don't claim to be an expert on ant. Please send comments and corrections.
Cascading actions from Parent to Child in Hibernate
It's long past time for me to discuss the cascade attribute in Hibernate's Collection support. Let's use the BeanShell to explore the behavior of a simple collection for various attribute values.
For reference, here is my abbreviated hibernate mapping file with the cascade element shown in bold:
<hibernate-mapping>
<class name="hb.KeySet"
table="keysets">
<id name="id" ... unsaved-value="-1">
<generator class="identity"/>
</id>
<property name="name" ... />
<property name="info" ... />
<set name="keys" ...
cascade="save-update" >
<key column="set_id"/>
<many-to-many class="hb.Keyword"
column="key_id"
/>
</set>
</class>
</hibernate-mapping>
The primary BeanShell scripted object was extended by adding the findAll method:
Collection findAll( String className )
{
return session.find( "from " + className );
}
And now we're ready to examine different values of the cascade element. We'll skip none, as we've already seen that Hibernate performs a shallow save when cascade="none".
- save-update: cascades save and update actions from the parent to the child.
-
Note that the id value of the child Keyword changes from the unsaved-value of -1 to 0 when the parent KeySet is changed. And that the delete action does not cascade to the child.
bsh % import hb.*; bsh % source("bsh/Hibernate.bsh"); bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print(hb.findAll("Keyword")); [] bsh % print(hb.findAll("KeySet")); [] bsh % ireland = new Keyword("Ireland"); bsh % country = new KeySet("Country"); bsh % country.add(ireland); bsh % print( country ); {-1:Country(null)|[-1:Ireland(null)]} bsh % hb.save( country ); bsh % print( country ); {0:Country(null)|[0:Ireland(null)]} bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % country = hb.findByName("KeySet",null); bsh % hb.delete( country ); bsh % tx.commit(); bsh % print( hb.findAll("Keyword") ); [0:Ireland(null)] bsh % print( hb.findAll("KeySet") ); [] - delete: cascades the delete action from the parent to the child.
-
In this example, it is necessary to explicitly save both the parent and the child (observe the value of the child's id field when the parent is saved first). The child Keyword is automatically deleted when the parent KeySet is saved.
bsh % import hb.*; bsh % source("bsh/Hibernate.bsh"); bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); [] bsh % ireland = new Keyword("Ireland"); bsh % country = new KeySet("Country"); bsh % country.add(ireland); bsh % hb.save(country); bsh % print( country ); {0:Country(null)|[-1:Ireland(null)]} bsh % hb.save(ireland); bsh % print( country ); {0:Country(null)|[0:Ireland(null)]} bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % country = hb.findByName("KeySet",null); bsh % hb.delete( country ); bsh % tx.commit(); bsh % print( hb.findAll("Keyword") ); [] bsh % print( hb.findAll("KeySet") ); []This example shows why you need to use delete with care – hibernate will attempt to delete children that are shared with existing parents.
bsh % tx = hb.transaction(); bsh % ireland = new Keyword("Ireland"); bsh % country = new KeySet("Country"); bsh % uk = new KeySet("United Kingdom"); bsh % country.add( ireland ); bsh % uk.add( ireland ); bsh % hb.save( ireland ); bsh % hb.save( country ); bsh % hb.save( uk ); bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % country = hb.findByName("KeySet","Country"); bsh % hb.delete(country); bsh % tx.commit(); // Error: // Uncaught Exception: Method Invocation tx.commit : at Line: 1 : in file: <unknown file> : tx .commit ( )
Target exception: net.sf.hibernate.JDBCException: could not delete: [hb.Keyword#1] - all: all actions are cascaded from the parent to the child.
-
All is the union of save-update and delete. It has the benefits of both (save and delete actions are propagated).
bsh % import hb.*; bsh % source ("bsh/Hibernate.bsh"); bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); [] bsh % ireland = new Keyword( "Ireland" ); bsh % country = new KeySet( "Country" ); bsh % country.add( ireland ); bsh % print( country ); {-1:Country(null)|[-1:Ireland(null)]} bsh % hb.save( country ); bsh % print( country ); {0:Country(null)|[0:Ireland(null)]} bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % country = hb.findByName("KeySet",null ); bsh % print( country ); {0:Country(null)|[0:Ireland(null)]} bsh % hb.delete( country ); bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); [] bsh % hb.close();And the downside of delete – hibernate will attempt to delete children that are shared with existing parents.
bsh % import hb.*; bsh % source("bsh/Hibernate.bsh"); bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); [] bsh % ireland = new Keyword("Ireland"); bsh % country = new KeySet("Country"); bsh % uk = new KeySet("United Kingdom"); bsh % country.add( ireland ); bsh % uk.add( ireland ); bsh % hb.save( country ); bsh % hb.save( uk ); bsh % tx.commit(); bsh % tx = hb.transaction(); bsh % country = hb.findByName("KeySet","Country"); bsh % print( country ); {0:Country(null)|[0:Ireland(null)]} bsh % hb.delete( country ); bsh % tx.commit(); // Error: // Uncaught Exception: Method Invocation tx.commit : at Line: 1 : in file:: tx .commit ( )
Target exception: net.sf.hibernate.HibernateException: Flush during cascade is dangerous - this might occur if an object was deleted and then re-saved by cascade (remove deleted object from associations)Note that delete actions do not cascade to orphan children.
bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print( hb.findAll("Keyword")); [0:Ireland(null)] bsh % print( hb.findAll("KeySet")); [{0:Country(null)|[0:Ireland(null)]}] bsh % ireland = hb.findByName("Keyword",null); bsh % country = hb.findByName("KeySet",null); bsh % country.remove( ireland ); bsh % hb.delete( country ); bsh % tx.commit(); bsh % print( hb.findAll("Keyword") ); [0:Ireland(null)] bsh % print( hb.findAll("KeySet") ); [] -
- all-delete-orphan: all actions are cascaded from the parent to the child, orphan children are deleted.
-
Child is removed from the parent. When the parent is saved [updated], the orphan child is deleted.
bsh % import hb.*; bsh % source( "bsh/Hibernate.bsh" ); bsh % hb = Hibernate(); bsh % tx = hb.transaction(); bsh % print ( hb.findAll("Keyword") ); [0:Ireland(null)] bsh % print ( hb.findAll("KeySet")); [{2:Country(null)|[0:Ireland(null)]}] bsh % country = hb.findByName("KeySet",null); bsh % ireland = hb.findByName("Keyword",null); bsh % country.remove(ireland); bsh % hb.save( country ); bsh % tx.commit(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); [{2:Country(null)|[]}]Child is removed from the parent. When the parent is deleted, the orphan child is deleted.
bsh % print( hb.findAll("Keyword") ); [1:Ireland(null)] bsh % print( hb.findAll("KeySet") ); [{2:Country(null)|[1:Ireland(null)]}] bsh % ireland = hb.findByName("Keyword",null); bsh % country = hb.findByName("KeySet",null); bsh % country.remove( ireland ); bsh % hb.delete( country ); bsh % tx.commit(); bsh % print( hb.findAll("Keyword")); [] bsh % print( hb.findAll("KeySet")); []
For my money, save-update is the winner here. If save-update-orphan-deletion (cascade save and update, delete orphans when necessary) existed, then that might be a strong second choice. This is a many-to-many relationship example, your mileage will vary for other relationships.
If you'd like to try these examples on your own, the cascading action example source is available. For the record, here's my current Java configuration.
Disclaimer: I don't claim to be an expert on hibernate. Please send comments and corrections.
Java Tutorial Woes
You need to walk before you can run. My Java Tutorials may be linked from the DMOZ beginner's level tutorial page, but I'd argue that Hibernate is an intermediate topic. So if you take my simple Hibernate application, change the database from the HSQLDB to HSQL and see the error message:
[java] net.sf.hibernate.HibernateException:
[java] JDBC Driver class not found: org.hsqldb.jdbcDriver
[java] at net.sf.hibernate. ...
[java] ...
[java] at Main.main(Unknown Source)
Then I really expect you to ask "Why is it looking for the HSQLDB JDBC driver (org.hsqldb.jdbcDriver) when I'm using HSQL?" on your own.