Building jboss services example, the indexer

This is a model for building all bedework services and may help for non-bedework service

In the non-jboss environment the indexer is a shell script that needs to be run by cron (for crawling) or as a background process as a listener.

For jboss we wrap it with an mbean. We can extend jboss specific classes, however, jboss recognizes the standard jmx mbean lifecycle methods and will deploy such a bean.

We need an interface !BwIndexerMBean and the associated implementation which MUST have the same name without "!MBean", BwIndexer. The interface defines attributes we want to make visible via the jmx console and also configure in the jboss-service.xml file. For the indexer the interesting attributes are the account we run under and the paths we skip. The interface looks like - comments removed for brevity:

public interface BwIndexerMBean {
  public void setAccount(String val);

  public String getAccount();

  public void setSkipPaths(String val);

  public String getSkipPaths();

  public String getName();

  public void start();

  public void stop();

  public boolean isStarted();
}

The implementation is a simple extension of the application BwIndexerApp? and looks like:

public class BwIndexer extends BwIndexApp implements BwIndexerMBean {
  private boolean started;

  public String getName() {
    return "org.bedework:service=Indexer";
  }

  public boolean isStarted() {
    return started;
  }

  public void start() {
    started = true;

    try {
      listen();
    } catch (Throwable t) {
      error(t.getMessage());
    }

    started = false;
  }

  public void stop() {
     ...
  }

  public void setSkipPaths(final String val) {
    String[] paths = val.split(":");

    for (String path:paths) {
      skipPaths.add(path);
    }
  }

  public String getSkipPaths() {
    String delim = "";
    StringBuilder sb = new StringBuilder();

    for (String s: skipPaths) {
      sb.append(delim);
      sb.append(s);

      delim = ":";
    }

    return sb.toString();
  }
}

We need to create a sar file, indexer.sar. JBoss allows us to define the structure of the sar. This allows us to use the indexer application structure as it stands. Inside the indexer.sar we have a classes folder which contains property and configuration files. We also have a lib folder containing the jars. We need to add a META-INF directory holding the jboss-service.xml file and the jboss-structure.xml file. So we have something like

indexer.sar/
indexer.sar/classes
indexer.sar/lib
indexer.sar/META-INF
indexer.sar/META-INF/jboss-service.xml
indexer.sar/META-INF/jboss-structure.xml

jboss-structure.xml for the indexer

If we adopt the same structure for all we can use the same jboss-structure.xml for all these services. That file looks like

<?xml version="1.0" encoding="UTF-8"?>
<structure>
  <context>
    <path name=""/>
    <metaDataPath>
      <path name="META-INF"/>
    </metaDataPath>        
    <classpath>
      <path name="classes"/>
      <path name="lib" suffixes=".jar" />
    </classpath>
  </context>
</structure>

jboss-service.xml for the indexer

This file defines the name of the service, the attribute to be made visible and any dependencies. This service requires the activemq connection factory to be deployed. Note that the text within the depends element can be copies straight out ofd the jboss log. Start jboss and then scan the log for the deployment of the resource you depend on. The text from the log message can then be used directly.

The file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<server>
  <!--  guarantee separate classloader -->
  <loader-repository> 
    org.bedework:archive=indexer-service 
  </loader-repository> 
  
  <mbean code="org.bedework.indexer.BwIndexer"
         name="org.bedework:service=Indexer">
    <attribute name="Account">admin</attribute>
    <attribute name="SkipPaths">/public/unbrowsable:/public/aliases</attribute>
    

    <!-- We need activemq -->    
    <depends>jboss.jca:service=ConnectionFactoryBinding,name=activemq/QueueConnectionFactory</depends>
    
    <!-- We also need the bedework database -->
    <depends>jboss.jca:service=DataSourceBinding,name=CalendarDS</depends>
  </mbean>
</server>

Other changes

Removed the resources directory with log4j.xml inside.

Remove the following from lib/

  • log4j*.jar
  • activemq-core*.jar
  • geronimo*.jar
  • jms-1.1.jar

Leaving these causes class cast exceptions