Installing JBoss Messaging on JBoss AS 4.2.3

JBoss Messaging is the new enterprise messaging system for JBoss AS. According to JBoss it is a complete rewrite of JBossMQ and offers improved performance and features. Since I will be using messaging in an upcoming project and JBoss AS 4.2.3 comes with JBossMQ I decided to upgrade my Application Server from JBossMQ to JBoss Messaging. The installation instructions weren’t real clear and I ran into a few snags so I thought I would share.

Here is my environment:

WARNING: These instructions are for a non-clustered JBoss messaging installation using the automated installation and is only to be used on a default installation of JBoss AS. If you have made any changes to the AS configuration files you will need to follow the JBoss Messaging manual installation instructions found in the documentation. The installation won’t overwrite any files but you won’t be able to use the messaging along with your custom configuration unless you perform the manual installation.

  • Make sure you have the JBOSS_HOME (root directory of your JBoss AS installation) environment variable setup. If you don’t have this set correctly your installation will fail. For example my variable looks like the following: JBOSS_HOME = C:\jboss-4.2.3.GA
  • Unzip the JBoss Messaging into a directory of your choice.
  • Open a command prompt and navigate the “util” directory which is nside the JBoss Messaging directory.
  • Type ant -f release-admin.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
c:\jboss-messaging-1.4.4.GA>cd util
c:\jboss-messaging-1.4.4.GA\util>ant -f release-admin.xml
Buildfile: release-admin.xml
default:
validate-jboss:
prevent-messaging-overwrite:
validate-messaging-artifact:
create-server-config:
[echo] Creating JBoss Messaging configuration 'messaging' for C:\jboss-4.2.3.GA based on configuration 'default' with jboss-messaging.sar
[mkdir] Created dir: C:\jboss-4.2.3.GA\server\messaging
[copy] Copying 602 files to C:\jboss-4.2.3.GA\server\messaging
[copy] Copied 106 empty directories to 1 empty directory under C:\jboss-4.2.3.GA\server\messaging
expand-sar:
[unjar] Expanding: c:\jboss-messaging-1.4.4.GA\jboss-messaging.sar into C:\jboss-4.2.3.GA\server\messaging\deploy\jboss-messaging.sar
[copy] Copying 1 file to C:\jboss-4.2.3.GA\server\messaging\lib
[copy] Copying 2 files to C:\jboss-4.2.3.GA\server\messaging\conf\props
[copy] Copying 1 file to C:\jboss-4.2.3.GA\server\messaging\deploy
[copy] Copying 1 file to C:\jboss-4.2.3.GA\server\messaging\deploy
BUILD SUCCESSFUL
Total time: 17 seconds
c:\jboss-messaging-1.4.4.GA\util>

If the installation was successfull you should now have a directory called “messaging” in JBOSS_HOME/server.

screenhunter_04-2009-07-22

  • You now need to set the SuckerPassword attribute value in the messaging-service.xml which is located in JBOSS_HOME/server/messaging/deploy/jboss-messaging.sar. WARNING: It is a SECURITY RISK to not set this password. This password should only be exposed to administrators.

1
2
3
<!-- The password used by the message sucker connections to create connections.
THIS SHOULD ALWAYS BE CHANGED AT INSTALL TIME TO SECURE SYSTEM-->
<attribute name="SuckerPassword">Enter your password here</attribute>

  • JBoss Messaging 1.4.4 requires a specific version of jboss-remoting.jar. On JBoss 4.2+ you have to use Remoting 2.2.3. Replace the jboss-remoting.jar file located in JBOSS_HOME/server/messaging/lib with the 2.2.3 jar file you downloaded.  NOTE: I lost a couple of hours of my life yesterday because I forgot this step. JBoss messaging will startup fine without this jar but you will get connection errors when you try and run the examples.
  • Edit the JBOSS_HOME/server/messaging/conf/standardjboss.xml and set CreateJBossMQDestination to false on every occurance. This disables the proxies that try to create a destination on JBoss MQ if they can’t find it on JNDI.

1
<CreateJBossMQDestination>false</CreateJBossMQDestination>
  • Edit the JBOSS_HOME/server/messaging/conf/jboss-service.xml and comment out the reference to JBoss MQ on JSR-77 Management Bean.

1
2
3
4
5
6
<!-- ==================================================================== -->
<!-- JSR-77 Single JBoss Server Management Domain -->
<!-- ==================================================================== -->
<mbean code="org.jboss.management.j2ee.LocalJBossServerDomain"
... Comment this line ...
<!-- <attribute name="JMSService">jboss.mq:service=DestinationManager</attribute> -->

  • Edit the JBOSS_HOME/server/messaging/conf/login-config.xml and comment out the jboss-mq security policies.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
### Comment these lines:
<!-- Security domain for JBossMQ -->
<!-- <application-policy name = "jbossmq">
<authentication>
<login-module code = "org.jboss.security.auth.spi.DatabaseServerLoginModule"
flag = "required">
<module-option name = "unauthenticatedIdentity">guest</module-option>
<module-option name = "dsJndiName">java:/DefaultDS</module-option>
<module-option name = "principalsQuery">
SELECT PASSWD FROM JMS_USERS WHERE USERID=?</module-option>
<module-option name = "rolesQuery">
SELECT ROLEID, 'Roles' FROM JMS_ROLES WHERE USERID=?</module-option>
</login-module>
</authentication>
</application-policy> -->
<!-- Security domain for JBossMQ when using file-state-service.xml
<application-policy name = "jbossmq">
<authentication>
<login-module code = "org.jboss.mq.sm.file.DynamicLoginModule"
flag = "required">
<module-option name = "unauthenticatedIdentity">guest</module-option>
<module-option name = "sm.objectname">jboss.mq:service=StateManager</module-option>
</login-module>
</authentication>
</application-policy>
-->


The installation and configuration is complete. Now it is time to start the server and test it.

  • Start the JBoss server using the messaging configuration.

1
2
C:\Users\BrianA>cd %JBOSS_HOME%/bin
C:\jboss-4.2.3.GA\bin>run.bat -c messaging

  • Now it is time to test the installation. Get to a command prompt and go to directory where you exploded the JBoss Messaging software. Once there, go to the examples/queue directory. Simply type ant and the test will run. NOTE: Apache Ant has to be installed and in the path for this to work.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
c:\jboss-messaging-1.4.4.GA\examples\queue>ant
Buildfile: build.xml
identify:
     [echo] ###########################################################################
     [echo] #                       Running the QUEUE example                         #
     [echo] ###########################################################################
     [echo] The queue:      testQueue
     [echo] The client jar: ../..//jboss-messaging-client.jar
sanity-check:
init:
compile:
run:
     [java] Queue /queue/testQueue exists
     [java] The message was successfully sent to the testQueue queue
     [java] Received message: Hello!
     [java] The example connected to JBoss Messaging version 1.4.4.GA (1.4)
     [java]
     [java] #####################
     [java] ###    SUCCESS!   ###
     [java] #####################
BUILD SUCCESSFUL
Total time: 2 seconds


NOTE: Keep in mind the default installation uses the Hypersonic database for message persistence. This is fine for testing but is not suitable for a production environment. Before moving to production you will need to configure the Messaging instance to use a database such as Oracle, MySQL, PostgreSQL, etc… which is beyond the scope of this post.



Soft deletes using Hibernate annotations.

blog-exampleI am currently working on a Seam application that has a need for soft deletes in the database. To the right you can see a snippet of my database diagram which contains a CUSTOMER and APP_USER table. This is just a straight forward one to many relationship but the important thing to note though is the “DELETED” field in each table. This is the field that will be used to track the soft delete. If the field contains a ‘1’ the record has been deleted and if it contains a ‘0’  the record hasn’t been deleted.

Before ORMs like Hibernate I would have had to track and set this flag myself using SQL. It wouldn’t be super hard to do but who wants to write a bunch of boilerplate code just to keep track of whether or not a record has been deleted. This is where Hibernate and annotations comes to the rescue.

Below are the 2 Entity classes that were generated by Hibernate using seamgen. I have omitted parts of the code for clarity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//Package name...

//Imports...

@Entity
@Table(name = "CUSTOMER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE customer SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@Where(clause="deleted <> '1'")
public class Customer implements java.io.Serializable {
private long id;
private Billing billing;
private String name;
private String address;
private String zipCode;
private String city;
private String state;
private String notes;
private char enabled;
private char deleted;
private Set appUsers = new HashSet(0);

//Constructors...

//Getters and Setters...

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "customer")
//Filter added to retrieve only records that have not been soft deleted.
@Where(clause="deleted <> '1'")
public Set getAppUsers() {
return this.appUsers;
}
public void setAppUsers(Set appUsers) {
this.appUsers = appUsers;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//Package name...

//Imports...

@Entity
@Table(name = "APP_USER")
//Override the default Hibernation delete and set the deleted flag rather than deleting the record from the db.
@SQLDelete(sql="UPDATE app_user SET deleted = '1' WHERE id = ?")
//Filter added to retrieve only records that have not been soft deleted.
@Where(clause="deleted <> '1'")
public class AppUser implements java.io.Serializable {
private long id;
private Customer customer;
private AppRole appRole;
private char enabled;
private String username;
private String appPassword;
private Date expirationDate;
private String firstName;
private String lastName;
private String email;
private String phone;
private String fax;
private char deleted;
private Set
persons = new HashSet(0);

//Constructors...

//Getters and Setters...
}

The following 2 steps is all that I had to do to implement the soft delete.

  1. Added the @SQLDelete annotation which overrides the default Hibernate delete for that entity.
  2. Added the @Where annotation to filter the queries and only return records that haven’t been soft deleted. Notice also that in the CUSTOMER class I added an @Where to the appUsers collection. This is needed to fetch only the appUsers for that Customer that have not been soft deleted.

Viola! Now anytime you delete those entities it will set the “DELETED” field to ‘1’ and when you query those entities it will only return records that contain a ‘0’ in the “DELETED” field.

Hard to believe but that is all there is to implementing soft deletes using Hibernate annotations.