caucho
Resin
FAQ
Reference Guide
Demo
Tutorial

JSP page
Config
URLs
Database Forms
XTP Copy
Hello Tag
Vary Filter
HardCore
Mailing Forms
Beans
Cache
XSL Filter
run-at
jndi app config
 Application configuration files using a custom JNDI object

run-at
Tutorial
 

  1. The java code for a custom JNDI object
  2. Configuring the custom JNDI object
  3. Obtaining and using the object

A common requirement is the need to read, and possibly write, configuration files for an application. An excellant way to accomplish this is to implement a custom JNDI object, which is easily configured and easily obtained from anywhere in the application.

This implementation of the concept allows you to configure a base directory for configuration files, and use the object obtained with a jndi lookup to open files relative to the base directory.

The java code for a custom JNDI object

A custom JNDI object is implemented similar to a java-bean. Setter methods like setFoo(String foo) are used to set values that are specified in the configuration.

In this case, a single setter is provided that matches the configuration parameter "config-files-location"

package example;

import java.net.*;
import java.io.*;

import com.caucho.vfs.*;

public class AppConfig {
  ConfigFilesLocation _cfl = null;

  /**
   * Set the base for subsequent call's to openConfigFileRead()
   * and openConfigFileWrite()
   *
   * @param location a file path or url
   */
  public void setConfigFilesLocation(String location)
    throws Exception
  {
    _cfl = new ConfigFilesLocation();
    _cfl.setLocation(location);
  }

  public void init()
    throws Exception
  {
    if (_cfl == null)
      throw new Exception("'config-files-location' must be set");
  }

  /**
   * Create and return a ReadStream for a configuration file, with
   * the file being relative to the base previously set with
   * setConfigFilesLocation()
   *
   * @return a WriteStream, which can be treated as a
   * java.io.InputStream if desired
   *
   * @see java.io.InputStream
   */
  public ReadStream openConfigFileRead(String file)
    throws IOException
  {
    return _cfl.openRead(file);
  }

  /**
   * Create and return an WriteStream for a configuration file, with
   * the file being relative to the base previously set with
   * setConfigFilesLocation().
   *
   * @return a WriteStream, which can be treated as a
   * java.io.OutputStream if desired
   *
   * @see java.io.OutputStream
   */
  public WriteStream openConfigFileWrite(String file)
    throws IOException
  {
    return _cfl.openWrite(file);
  }

  public static class ConfigFilesLocation {
    Path _path;  // com.caucho.vfs.Path

    public void setLocation(String location) 
    {
      _path = Vfs.lookup(location);
    }

    public ReadStream openRead(String file)
      throws IOException
    {
      Path p = _path.lookup(file);
      return p.openRead();
    }

    public WriteStream openWrite(String file)
      throws IOException
    {
      Path p = _path.lookup(file);
      return p.openWrite();
    }
  }
}

Configuring the custom JNDI object

Configuration of the JNDI object is done with the resource-ref tag.

The example here configures the location of the configuration files as WEB-INF/config (which means you need to make sure the directory exists for the example to work). It is good to hide the files somewhere under WEB-INF, because a browser will not be able to read the files, just the application.

<web-app>
  <!-- make an example.AppConfig object, available with the
     - JNDI name "java:comp/env/config/Application"
    -->
  <resource-ref res-ref-name='config/Application'
                class-name='example.AppConfig'>
    <!-- config-files-location
       -
       - set's the base for subsequent config file lookups.
       -
       - EL variables are very useful here, such as 
       - app.appDir, server.rootDir, host.rootDir
       - See http://www.caucho.com/resin-3.0/config/el.xtp 
       -
       - You can also use an http url, although you will not be able
       - to write files then.
      -->
    <init-param config-files-location='${'${'}app.docDir}/WEB-INF/config'/>
    <!-- <init-param config-files-location='http://gryffindor/config'/> -->
  </resource-ref>

  ...

</web-app>

Obtaining and using the object

An instance of the object is retrieved in the application using JNDI. Since the configuration will not change, it is best to store the results of the lookup.

In this example servlet, an instance of the object is retrieved in the init() method and then used in the doGet() to open the configuration files for reading and writing.

package example;


import javax.servlet.*;
import javax.servlet.http.*;

import java.io.*;
import java.util.*;
import javax.naming.*;

public class TestAppConfig extends HttpServlet {
  AppConfig _appConfig;
  final static String _jndi_name = "java:comp/env/config/Application";

  public void init()
    throws ServletException
  {
    try {
      _appConfig = (AppConfig) new InitialContext().lookup(_jndi_name);

      if (_appConfig == null)
        throw new ServletException("`" + _jndi_name + "' is an unknown JNDI resource");
    } catch (NamingException e) {
      throw new ServletException(e);
    }
  }

  public void doGet(HttpServletRequest req,
                    HttpServletResponse res)
    throws IOException, ServletException
  {
    res.setContentType("text/html");
    PrintWriter out = res.getWriter();

    String inputFile = req.getParameter("inputFile");
    String outputFile = req.getParameter("outputFile");

    out.println("<html><head><title>TestAppConfig</title></head><body>");

    if (inputFile != null && inputFile.length() > 0) {
      // demonstration of reading a configuration file
      out.println("<h2>inputFile: " + inputFile + "</h2>");
      try {
        // copy the input file to the output
        InputStream is = _appConfig.openConfigFileRead(inputFile);
        final int bufsz = 1024;
        char[] buf = new char[bufsz];
        int l;

        Reader in = new BufferedReader(new InputStreamReader(is));

        out.println("<pre>");
        while ((l = in.read(buf,0,bufsz)) > 0) {
          out.write(buf,0,l);
        }
        out.println("</pre>");
      } catch (Exception ex) {
        throw new ServletException(ex);
      }
    } else if (outputFile != null && outputFile.length() > 0) {
      // demonstration of writing a configuration file
      out.println("<h2>outputFile: " + outputFile + "</h2>");
      try {
        OutputStream os = _appConfig.openConfigFileWrite(outputFile);
        PrintWriter outfile = new PrintWriter(os);
        Date now = new Date();
        outfile.print("Configuration file made from 'TestAppConfig' ");
        outfile.println(now);
        outfile.close();
      } catch (Exception ex) {
        throw new ServletException(ex);
      }
      String url = res.encodeURL(req.getRequestURI() + "?inputFile=" + outputFile);
      out.println("The configuration file has been written.");
      out.println("You can now <a href='" + url + "'>view it as an inputFile</a>");
    } else {
      outputFile = "test.txt";
      String url = res.encodeURL(req.getRequestURI() + "?outputFile=" + outputFile);
      out.println("Try <a href='" + url + "'>writing to a configuration file</a>");
    }
  }
}

To enable the servlet, you can add the following to WEB-INF/web.xml, and the url will be (for example) http://localhsot:8080/myapp/test

  <servlet>
    <servlet-name>test</servlet-name>
    <servlet-class>example.TestAppConfig</servlet-class>
  </servlet>

  <servlet-mapping>
    <url-pattern>/test</url-pattern>
    <servlet-name>test</servlet-name>
  </servlet-mapping>


run-at
Tutorial
 
Copyright © 1998-2002 Caucho Technology, Inc. All rights reserved.
Resin® is a registered trademark, and HardCoretm and Quercustm are trademarks of Caucho Technology, Inc.