Monday, April 2, 2012

Automatically reload log4j configuration

I have been using Log4j for a while and IMO it is one of the greatest libraries to trace your application behaviour. Yet, I used to have this recurring problem, when I wanted to change logger configuration, my application was running and I couldn't restart it to reload loggers. But then one day I have found a solution, which turned out to be very simple and provided out of the box with the library.

Here is an example of a simple class, which can be used at the very beginning of any Java application to setup Log4j configuration. Configuration may be located wherever we want and it doesn't need to be named as default "log4j.properties".

public abstract class LoggerSetup {

    private static Logger logger;
    // Period in [ms] between checking for logger properties change
    private static final long CHECK_PERIOD = 20000;

    /**
     * Set logger file properties
     * @param filename - path to log4j properties file
     */
    public static void setLogger(String filename) {
        File f = new File(filename);
        if (f.exists()) {
            PropertyConfigurator.configureAndWatch(filename, 20000);
        }
        logger = Logger.getLogger(LoggerSetup.class);
        logger.debug("Setup logger");
    }

}

As we can see, every 20 seconds, Log4j check whether properties file has changed. If so, it will reload logger setup. It means that during application execution you may change logger levels, appenders, formats etc. without the need
for application restart.

JavaFX 2.1 example on Linux x64

JavaFX 2.1 Developer Preview for Linux has been released recently, unfortunately only for 32bit architecture. But what about x64? Well, I have Ubuntu x64 10.04 LTS and it also works :D! Here are the tips to run BrickBreaker example, which comes with JavaFX SDK examples.

To download SDK preview we should look at proper download section here. Also we need to download latest JavaSE JDK 7 but for Linux x86 (despite the fact we are using 64-bit Linux). After downloading all necessary packages, just unpack them wherever you want.

Right now JavaFX SDK examples are distributed in separate package. It is available at the bottom of this page (notice that we need examples for Linux!). Inside package we may find src directory with BrickBreaker sources, a simple game which we will compile and run.

The easiest choice of IDE for latest JavaFX release is Netbeans 7. To be able to run and compile FX projects we need to setup Java platforms. Just select "Tools->Java Platforms" from the menu. Click "Add platform..." and select directory when we have extracted JavaSE JDK 7, then select "Finish". We have added new JVM, but we need to enable FX. Select new added Java platform in "Java Platform Manager" window and navigate to "JavaFX" tab. Enable JavaFX and point to JavaFX SDK directory by clicking "Browse..." next to "JavaFX SDK:" input.

Now we can open BrickBreaker project in NetBeans and open its properties window. Navigating to "Libraries" section in "Project Properties" window we should select Java platform with enabled JavaFX libraries. Then we can compile and run project right from IDE.

Thursday, February 9, 2012

JSF 1.2 download file link with managed bean

Recently I had to use in one of my JSF projects a download link for binary file from server. I didn't want to use my own servlet class, but instead just managed bean. I have done it several times before, but I always forget the proper code :) So here it is, maybe someone will find it useful ;)

public class DownloadManagedBean {

  /**
   * This is the action listener method
   */
  public void downloadAction(ActionEvent event) {
     // Get data from any source you want :)
     byte [] data = ...; 
     downloadAction("out.bin", data);  
  }

  /**
   * This is the core of download action
   */
  protected void downloadAction(String filename, byte[] data) {
        FacesContext faces = FacesContext.getCurrentInstance();
        HttpServletResponse response = (HttpServletResponse) faces.getExternalContext().getResponse();
        response.setContentLength(data.length);
        response.addHeader("Content-Type", "application/x-force-download");
        response.addHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
        ServletOutputStream out = null;
        try {
            long length = data.length;
            out = response.getOutputStream();
            response.setContentLength((int) length);
            out.write(data, 0, (int) length);
        } catch (Exception ex) {
            System.err.println(ex);
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception ex) {
                    System.err.println(ex);
                }
            }
        }
        // The most important line - finish response as we have already
        // close output stream response writer
        faces.responseComplete();
    }
}

To use above bean, we just put the following code inside JSF page source:

<h:form>
  <h:commandlink actionlistener="#{downloadManagedBean.downloadAction}" immediate="true" target="_blank" value="Download">
  </h:commandlink>
</h:form>

We could change downloadAction method to be more flexible, by using buffered streams and files as data sources, that may be located anywhere in the server's local filesystem. Above example uses for simplicity byte array only to show the main idea how to make it work.

Wednesday, January 25, 2012

Java FX 2.0 released

A new JavaFX 2.0 has been released! I remember that I have been trying for a while to work with previous versions 1.1 and 1.2, and to be honest it was horrible experience. I did that because I have been searching for the tool which allows to create true multimedia application in JAVA. Also I wanted to create a very nice GUI. Well I think that previous versions of JavaFX were completely failures...

Need to check 2.0 though, because I saw some video tutorials and it looks really nice!

UPDATE

So I could not resist myself and today I downloaded JDK 1.7u2 (with JavaFX 2.0 support) and NetBeans 7.1. Unfortunately I had to work on Windows, because I could not find proper version of JavaFx SDK for 64bit Linux, on which I usually work. I managed to do some simple tutorials from http://docs.oracle.com/javafx/index.html.

My first impression is that the whole API is very simple and in a few lines of code we get really nice GUI! What is more, there is also a set of classes that allows to integrate Swing with JavaFX. Not to mention about using CSS for application skinning and creating application layouts and components inside XML files. Oh! And there is even a possibility to use for example JavaScript or Groovy to write applications' logic!

Looking forward to JavaFX 2.0 for 64bit Linux architecture. Finally we can create nice looking desktop application in Java, which can also handle multimedia content as well. It is time to start thinking about rewriting my old Swing projects :)

Tuesday, January 17, 2012

Bash Shell in Java: “Cannot run program ”/bin/bash“: java.io.IOException: error=24, Too many open files”

Recently i have faced a problem as in the title. I was using JAVA's ProcessBuilder class, which allows to use bash shell and its scripts. Unfortunately my program after a while started to log that it "Cannot run program".

If you encounter similar problem, googling a while will give you plenty of pages with some more or less accurate solutions. Most of them will tell to check how many files are currently open in the system (by unix command lsof) and how's that number related to your system limit (check by bash command ulimit -n). Increasing maximum number of open files at a time is short-term solution in my opinion.

Let's get back to the core of problem. In my code I was using below lines:

ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
pb.redirectErrorStream(true); // use this to capture messages sent to stderr
Process shell = pb.start();
InputStream shellIn = shell.getInputStream(); // this captures the output from the command
int shellExitStatus = shell.waitFor(); // wait for the shell to finish and get the return code
InputStreamReader reader = new InputStreamReader(shellIn);
BufferedReader buf = new BufferedReader(reader);
// Read lines using buf

After using new ProcessBuilder and reader of input stream we must assure that InputStreamReader will be closed after reading as it should release any associated files. So I have added following lines:

if(reader != null) {
  try {
    reader.close();
  } catch (IOException ex) {
    log.error(ex, ex);
  }
}
if(shellIn != null) {
  try {
    shellIn.close();
  } catch (IOException ex) {
    log.error(ex, ex);
  }
}

Above code should be used in finally block. This solution works but not always, because it will not close all pipes and subprocesses triggered by shell command. For example when I have used

ps aux | grep java | awk '{if($1=="root") print $11}' | grep test | wc -l

I was creating multiple unnamed pipes, which stayed open and were increasing the total number of open files. To cleanup after executing shell command all subprocesses have to be stopped:

if(shell != null) {
  try {
    shell.destroy();
  } catch (Exception ex) {
    log.error(ex, ex);
  }
}

Destroying all subprocesses will do the thing. It will not impact on the result of shell command as in the code we have following line

int shellExitStatus = shell.waitFor();

To summarize, if we want to avoid this problem we should use something similar to below function:

  public String bashCommand(String command) {
        ProcessBuilder pb = new ProcessBuilder("bash", "-c", command);
        pb.redirectErrorStream(true); // use this to capture messages sent to stderr
        Process shell = null;
        String result = "";
        InputStream shellIn = null;
        InputStreamReader reader = null;
        try {
            shell = pb.start();
            shellIn = shell.getInputStream(); // this captures the output from the command
            int shellExitStatus = shell.waitFor();
            reader = new InputStreamReader(shellIn);
            BufferedReader buf = new BufferedReader(reader);
            String line;
            while ((line = buf.readLine()) != null) {
                result += line + "\n";
            }
        } catch (InterruptedException ig) {
            // Handle error
        } catch (IOException ignoreMe) {
            // Handle error
        } finally {
            if(reader != null) {
                try {
                    reader.close();
                } catch (IOException ex) {
                    // Handle error
                }
            }
            if(shellIn != null) {
                try {
                    shellIn.close();
                } catch (IOException ex) {
                    // Handle error
                }
            }
            if(shell != null) {
                try {
                    shell.destroy();
                } catch (Exception ex) {
                    // Handle error
                }
            }
        }
        return result;
    }

That's all. Hope it will help :)