When developing it’s easy to get distracted while waiting for a Java Application Server to restart.
Inspired by Ben Ellingson I went looking for a way to get Growl notifications when my local JBoss server had started. I couldn’t find much so I threw a java solution together such that whenever your JBoss server has started or shuts down you get a notification like:

I think this might be useful to others, so the code is below and the installation instructions for JBoss 5 are:
- If you don’t already have them, install growl and growlnotify http://growl.info/extras.php#growlnotify
- Copy the compiled Growler.class (remove .odt from this) and Growler.command (remove .odt from this) to <JBOSS_HOME>/bin
- Configure the last line in Growler.command, the options are:
- -u Specify the username for JBoss authentication(defaults to admin)
- -p Specify the password for JBoss authentication(defaults to admin)
- -s Use sticky growl notification windows(defaults to not sticky)
- -i The location of the JBoss Developer Studio.ico file (defaults to /Applications/jbds/eclipse/jbds.ico)
- If you want to run Growler on demand simply launch Growler.command whenever you launch eclipse
- However if you want Growler to always be running you’ll need to create a Launch Agent, to do so:
- Copy the attached info.sordyl.Growler.plist (remove .odt from this) to your user Launch Agent folder at ~/Library/LaunchAgents/
- Open your copy of info.sordyl.Growler.plist
- Edit Item 0 under ProgramArguments and update YOUR_JBOSS_HOME_PATH to point to where your Growler.command file lives in <JBOSS_HOME>/bin

Here is the Growler.java source as well; the code can be easily modified to monitor for changes in any JMX property, to access other JMX enabled servers or to access remote server(s). As written this assumes JBoss 5.x.
import gnu.getopt.Getopt;
import java.io.IOException;
import java.util.ArrayList;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.naming.CommunicationException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.security.SecurityAssociation;
import org.jboss.security.SimplePrincipal;
/**
*
* Install growl and growlnotify http://growl.info/extras.php#growlnotify
*
* usage: Growler [options]
* -u <name> Specify the username for authentication
* -p <name> Specify the password for authentication
* -s Use sticky growl notification windows
* -i <filepath> The location of the JBoss Developer Studio .ico file
*
* @author <a href="mailto:brent.sordyl@amentra.com">Brent Sordyl</a>
*/
public class Growler {
// Use sensible defaults for all properties
private String username = "admin";
private String password = "admin";
private int pollingFrequency = 3;
private String jbdsIconLocation = "/Applications/jbds/eclipse/jbds.ico";
private String growlTitle = "JBoss Application Server";
private String serverStartedMessage = "Server Started";
private String serverShutdownMessage = "Server is shutting down";
private boolean stickyGrowlNotifications = false;
private String jndiUrl = "jnp://localhost:1099";
public Growler(String[] args) {
processArguments(args);
}
/**
* The main method that checks for changes in
* server state and sends growl notifications.
*
* @param args the command line arguments
*/
public static void main(String[] args) {
Growler g = new Growler(args);
boolean lastStatus = false;
while (true) {
try{
boolean currentStatus = g.isJBoss5Up();
if ( (currentStatus != lastStatus) && currentStatus) {
sendNotification(g.growlTitle, g.serverStartedMessage, g.jbdsIconLocation, g.stickyGrowlNotifications);
} else if (currentStatus != lastStatus) {
sendNotification(g.growlTitle, g.serverShutdownMessage, g.jbdsIconLocation, g.stickyGrowlNotifications);
}
lastStatus = currentStatus;
Thread.sleep(g.pollingFrequency * 1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* Checks if the JBoss 5 server is up, this
* will need to change for JBoss 6 per
* http://community.jboss.org/wiki/WhichRemoteInterfaceShouldIUseForTheMBeanServer
*
* @return true, if is server up
* @throws Exception the exception
*/
private boolean isJBoss5Up() throws Exception
{
boolean up = false;
try {
SecurityAssociation.setPrincipal(new SimplePrincipal(username));
SecurityAssociation.setCredential(password);
System.setProperty("java.naming.provider.url", jndiUrl);
System.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory");
System.setProperty("java.naming.provider.url.pkgs", "org.jboss.naming");
System.setProperty("java.naming.provider.url.pkgs", "org.jnp.interfaces");
InitialContext ctx = new InitialContext();
MBeanServerConnection server = (MBeanServerConnection) ctx.lookup("jmx/invoker/RMIAdaptor");
up = Boolean.parseBoolean((server.getAttribute(new ObjectName("jboss.system:type=Server"), "Started")).toString());
} catch (CommunicationException ce) {} // Exception expected when server is shutdown
catch (NamingException ne) {} // Exception expected when server is starting or stopping
return up;
}
/**
* Sends a growl notification using growlnotify.
*
* @param title the title
* @param message the message
* @param jbdsIconLocation the jbds icon location
* @param sticky the sticky
*/
private static void sendNotification(String title, String message, String jbdsIconLocation, boolean sticky) {
ArrayList<String> args = new ArrayList<String>();
args.add("growlnotify");
args.add("-m");
args.add(message);
args.add("--image");
args.add(jbdsIconLocation);
args.add("-t");
args.add(title);
if (sticky)
args.add("-s");
try {
@SuppressWarnings("unused")
Process exec = Runtime.getRuntime().exec( args.toArray(new String[] {}) );
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Process command line arguments
* to override default values.
*
* @param args the command line args to parse
*/
private void processArguments(final String[] args) {
try {
String sopts = "u:p:i:s";
Getopt getopt = new Getopt("Growler", args, sopts);
int code;
while ((code = getopt.getopt()) != -1) {
switch (code) {
case 'u':
username = getopt.getOptarg();
break;
case 'p':
password = getopt.getOptarg();
break;
case 's':
stickyGrowlNotifications = true;
break;
case 'i':
jbdsIconLocation = getopt.getOptarg();
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}