Start blogging

Hi there! This is my latest blog, where I am going to "log" things that interest me the most and may be useful not only for myself :)

Eclipse with CUDA

Working with CUDA code in Eclipse is easy. There are some steps we need to setup in our IDE to start developing applications in pure C/C++ with CUDA support.

Showing posts with label Java tips. Show all posts
Showing posts with label Java tips. Show all posts

Wednesday, 26 September 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.

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.

Bash Shell in Java: error=24, Too many open files


Bash Shell in Java: “Cannot run program ”/bin/bash“: java.io.IOException: error=24, Too many open files”.
If you happen to see above error in your logs, there is a simple solution to fix this. It is only a matter of few lines in your code.

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 :)