Sunday, December 27, 2009

Using Hermes to Browse WebLogic Topics/Queues

Hermes is a useful tool which allows you to browse JMS topics and queues. I use WebLogic as my JMS provider and it was not trivial trying to connect to my topic using Hermes, so I thought I'd post instructions to help others trying to do the same.

Here are the steps you need to take, in order to browse WebLogic queues and topics using Hermes:

1. Install HermesJMS

  • Download Hermes from here.
  • It comes as an installer jar file which you can run using the command: java -jar hermes-installer-1.13.jar.
  • Once installed, start it using hermes.bat.

2. Add WebLogic Provider
You need to add the weblogic jar to the classpath as follows:

  • On the menubar go to Actions > New > New session... to open the Preferences dialog.
  • Click on the Providers tab.
  • Right-click to Add Group and call it "weblogic92", for example.
  • Right-click on Library to Add JAR(s) and select your weblogic jar file from the file chooser dialog.
  • Select Don't Scan when prompted to scan the jar file.
  • Click Apply and close the dialog.
3. Create WebLogic Session
  • On the menubar go to Actions > New > New session... to open the Preferences dialog.
  • Click on the Sessions tab.
  • Type a name for the session. For example, "myweblogic".
  • In the Plug In list select BEA WebLogic.
  • Under Connection Factory class, pick hermes.JNDITopicConnectionFactory.
  • Select weblogic92 (defined in step 2) from the Loader dropdown.
  • Add property: initialContextFactory with a value of weblogic.jndi.WLInitialContextFactory.
  • Add property: providerURL with a value of your URL e.g. t3://myhost:2120.
  • Add property: binding with a value of the name of your connection factory e.g. myConnectionFactory.
  • Add any other properties you may have e.g. securityCredentials etc.
  • Remove all Destinations by right-clicking and selecting Remove.
  • Press OK.
4. Discover Topics/Queues
  • On the left navigation tree, go into jms > sessions > myweblogic.
  • Right-click "myweblogic" (the new session created in step 3), and click Discover. You will see a list of queues and topics appear.
  • Click on any one of them to browse.

Friday, December 25, 2009

Generics and Class.forName

This post shows how you can create objects of a specified class, using a class name and the supertype of the class you are trying to create.
public final class BeanCreator {

  /**
   * Suppress constructor.
   */
  private BeanCreator(){
  }

  /**
   * Creates an object of the class name and supertype.
   * @param <T>
   * @param className
   * @param superType
   * @return
   * @throws ClassNotFoundException
   */
  public static <T> T create(final String className,
             final Class<T> superType) throws Exception {
    final Class< ? extends T> clazz =
         Class.forName(className).asSubclass(superType);
    return create(clazz);
  }

  /**
   * Creates an object of the specified class using
   * its public or private no-arg constructor.
   *
   * @param <T>
   * @param classToCreate
   * @return
   */
  public static <T> T create(final Class<T> classToCreate)
                                      throws Exception {
        final Constructor<T> constructor =
                   classToCreate.getDeclaredConstructor();
        if (constructor == null) {
         throw new Exception("Could not create a new "+
         "instance of the dest object: " + classToCreate
         + ".  Could not find a no-arg constructor.");
        }

        // If private, make it accessible
        if (!constructor.isAccessible()) {
            constructor.setAccessible(true);
        }
        return constructor.newInstance();
  }
}

Wednesday, October 21, 2009

Bash Globbing

Globbing refers to the expansion of shell metacharacters to complete file names. For example, when you run ls *, the shell expands the wildcard * into a list of files and passes them as arguments to ls.
sharfah@starship:~> ls *
file1 File2
Dot Globbing
By default, Bash does not glob dot-files. This means that ls * will not pick up any files beginning with the dot (.) character. However, it is easy to change this by doing the following:
sharfah@starship:~> shopt -s dotglob
sharfah@starship:~> ls *
.dotFile1 file1 File2
Case-Insensitive Globbing
There is also an option to turn on case-insensitive globbing:
sharfah@starship:~> shopt -s nocaseglob
sharfah@starship:~> ls f*
file1 File2
To view a list of all your shell options, type shopt.

Wednesday, October 14, 2009

Remote Debugging Java Applications

This is a quick post to show how you can connect to a remote Java virtual machine for debugging. I'm always forgetting the properties!

1. Add JVM Properties
Add the following properties to your java process before starting it up. This will tell it to accept debug connections.

-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=4001,suspend=y
2. Connect to Remote JVM through Eclipse
  • Go to your Eclipse Debug Configurations and create a new Remote Java Application configuration.
  • In Connection Type, choose Standard (Socket Attach).
  • Set the host to the machine where your Java application is running.
  • Set the port to the debug port specified in the JVM properties e.g. 4001.
  • Press Debug to start debugging.

Friday, October 02, 2009

Using log4j's FallbackErrorHandler

Our applications currently use a DailyRollingFileAppender for logging, but since they run on NFS across a number of different servers, we quite often get errors due to stale NFS file handles, when log4j tries to write to the files. We sometimes also get errors if the logging mount point is missing on some of the servers.

I've been trying to find a way to switch to a different appender (such as a ConsoleAppender), if log4j fails to write to the log files. At first I thought of writing my own custom appender, to wrap up a FileAppender and a ConsoleAppender, and to switch to the ConsoleAppender if the FileAppender threw an IOException, but then I came across the FallbackErrorHandler, which allows you to configure a backup appender, which takes over if the primary appender fails for whatever reason.

This is how you can set up your log4j.xml file to use a FallbackErrorHandler:

1. Create a backup appender:
The backup appender will be used if the primary appender fails. My backup is a ConsoleAppender:

  <appender name="console" class="org.apache.log4j.ConsoleAppender">
    <param name="Target" value="System.out"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %-5p %30.30c - %m%n"/>
    </layout>
  </appender>
2. Add a FallbackErrorHandler to your primary appender:
My primary appender is a DailyRollingFileAppender. Add a FallbackErrorHandler to it and tell it to use the "console" (backup) appender, using the appender-ref tag. The root-ref tag refers to the logger that is currently using that appender. If you have a different logger use the logger-ref tag to refer to it instead.
  <appender name="file" class="org.apache.log4j.DailyRollingFileAppender">
  <errorHandler class="org.apache.log4j.varia.FallbackErrorHandler">
       <root-ref/>
       <appender-ref ref="console"/>
  </errorHandler>
    <param name="File" value="C:/temp/test.log"/>
    <layout class="org.apache.log4j.PatternLayout">
      <param name="ConversionPattern" value="%d %-5p %30.30c - %m%n"/>
    </layout>
  </appender>
3. Trying it out:
To test this works, make your log file read-only, or change the path of the file to one which doesn't exist. When you run your application, you will see log4j print an error to stderr, and start logging to console, instead of file. If you turn log4j debug on you will see the message: "FB: INITIATING FALLBACK PROCEDURE." before console logging begins.

The complete log4j.xml configuration:
Here is my complete config file. (I tried setting up a log4j.properties file, but ran into problems and wasn't able to.)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    <appender name="console" class="org.apache.log4j.ConsoleAppender">
        <param name="Target" value="System.out" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p %30.30c - %m%n" />
        </layout>
    </appender>
    <appender name="file" class="org.apache.log4j.DailyRollingFileAppender">
        <errorHandler class="org.apache.log4j.varia.FallbackErrorHandler">
            <root-ref />
            <appender-ref ref="console" />
        </errorHandler>
        <param name="File" value="C:/temp/test.log" />
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" value="%d %-5p %30.30c - %m%n" />
        </layout>
    </appender>
    <root>
        <level value="INFO" />
        <appender-ref ref="file" />
    </root>
</log4j:configuration>