Caucho maker of Resin Server | Application Server (Java EE Certified) and Web Server


 

Resin Documentation

home company blog wiki docs 
app server web server 
health cloud java ee pro 
 Resin Server | Application Server (Java EE Certified) and Web Server
 

setter injection bean patterns


Resin configures beans using setter injection patterns, supporting the Inversion-of-Control design pattern. A "bean" is any plain-old Java object which follows standard configuration patterns. Because Resin can find the bean-style setters from looking at the class, it can configure those setters in a configuration file like the web.xml.

Resin's configuration follows the Assembly Line or Dependency Injection pattern.

Overview

The Assembly Line pattern gives configuration responsibility to the container where it belongs, while keeping the application code independent of the container. Bean-style configuration setters for simple properties form the foundation for the Assembly Line pattern. If an application follows the bean patterns, it can be configuration in any container following the Assembly Line (setter injection) pattern.

We strongly recommend following the Assembly Line pattern throughout an application, even if your application does not use Resin to configure itself. Following the Assembly Line pattern makes application code easier to understand, maintain, configure and test.

Property Configuration: setXXX

The bean configuration form the foundation of the Assembly Line pattern. Since most applications already follow the bean patterns, they get property configuration with no changes.

Each configuration parameter foo has a corresponding setter method setFoo with a single argument for the value. Resin looks at the class using Java's reflection to find the setFoo method.

Bean-style configuration for a single value setter
<init>
  <greeting>Hello, World!</greeting>
  <another-greeting>Hello, Mom!</another-greeting>
</init>
Bean-style java code for a single value setter
public class MyBean {
  private String _greeting;
  private String _anotherGreeting;

  public void setGreeting(String greeting) 
  {
    _greeting = greeting;
  }

  public void setAnotherGreeting(String anotherGreeting) 
  {
    _anotherGreeting = anotherGreeting;
  }
}

Setter Injection: setXXX

Setter injection connects resources following the same bean-style setter pattern. Where bean properties configure simple values like strings and integers, setter injection configures other resources like databases and application components.

Resin uses JNDI to store the intermediate resources, e.g. storing a database in java:comp/env/jdbc/test. The configuration file specifies the JNDI resource using the JSP expression language and jndi:lookup.

Configuration for Setter Injection
<init>
  <data-source>\${jndi:lookup("jdbc/test")}<data-source>
</init>
Setter Injection for a DataSource
public class MyBean {
  private DataSource _dataSource;

  public void setDataSource(DataSource ds)
  {
    _dataSource = ds;
  }
}

Compatibility

Setter injection is portable to containers which support dependency injection.

Container Properties: addXXX

Resources often act as containers for lists of values and map values. The addXXX pattern adds multiple values for a single property.

A setter method addFoo allows multiple values to be specified from the configuration.

Bean-style configuration for setting multiple values
<init>
  <greeting>Hello, World!</greeting>
  <greeting>Hello, Mom!</greeting>
</init>
Bean-style java code for setting multiple values
public class MyBean {
  private LinkedList _greetings = new LinkedList();

  public void addGreeting(String greeting) 
  {
    _greetings.add(greeting);
  }

}

Validation and Assembly: @PostConstruct

Well-written resources will validate their configuration and may perform additional assembly tasks. Resin calls @PostConstruct methods after all the setter methods have been called.

Bean-style @PostConstruct
public class MyBean {
  private String _language;
  private String _country;
  Locale locale;

  public void setLanguage(String language) 
  {
    _language = language;
  }

  public void setCountry(int country) 
  {
    _country = country;
  }

  @PostConstruct
  public void init()
  {
    locale = new Locale(language, country);
  }
}

Validation Exceptions

If an exception is thrown from any of the methods in the bean, Resin will attach a file name and line number that correspond to the configuration file.

Bean-style exceptions
public class MyBean {
  private String _language;
  private String _country;
  Locale _locale;

  public void setLanguage(String language) 
    throws Exception
  {
    if (language.length() != 2)
      throw new Exception("'language' must be a two-character string");
    _language = language;
  }

  public void setCountry(int country) 
    throws Exception
  {
    if (country.length() != 2)
      throw new Exception("'country' must be a two-character string");
    _country = country;
  }

  @PostConstruct
  public void init() 
  {
    if (_country == null)
      throw new Exception("'country' is required");
    if (_language == null)
      throw new Exception("'language' is required");

    _locale = new Locale(language,country);
  }
}
500 Servlet Exception

WEB-INF/web.xml:9: java.lang.Exception: 'country' must be a two-character string

Nested Beans: createXXX

Beans can be nested, allowing a bean to have setters that have other sub-beans as the type.

Bean-style configuration for sub-beans
<init>
  <table>
    <name>Foo</name>
    <timestamp-field>tstamp</timestamp-field>
  </table>

  <table name="Bar" timestamp-field="ts"/>
</init>
Bean-style java code for sub-beans
// a class to periodically clean old log records from the database
public class LogCleaner {
  List _logTables = new LinkedList();

  // the createXXX method is optional, and allows use something other than
  // the default constructor for a sub-bean
  public LogTable createTable()
  {
    return new LogTable();
  }

  // you could also use setTable(LogTable logTable)
  public void addTable(LogTable logTable)
  {
    _logTables.add(logTable);
  }

  public class LogTable {
    String _name;
    String _timestampField;

    public void setName(String name)
    {
      _name = name;
    }

    public void setTimestampField(String timestampField)
    {
      _timestampField = timestampField;
    }

    @PostConstruct
    public void init()
        throws Exception
    {
      if (_name == null)
        throw new Exception("'name' is required");
      if (_timestampField == null)
        throw new Exception("'timestamp-field' is required");
    }

    public void cleanTable(DataSource pool)
    {
      Connection conn = null;
      try {
        conn = pool.getConnection();
        ...
      } catch (SQLException e) {
        throw new ServletException(e);
      } finally {
        try {
          if (conn != null)
            conn.close();
        } catch (SQLException e) {
        }
      }
    }
  }

  ...
 
}

Setting with the body text

The addText() method will capture the body of the tag for a bean setter.

Bean-style configuration for setting with the body text
<init>
  <message>This is the message</message>
</init>
Bean-style java code for setting with the body text
public class MyBean {
  Message _msg;

  public Message createMessage() { return new Message(); }

  public void setMessage(Message msg) { _msg = msg; }

  public class Message {
    String _text;
    public void addText(String text) { _text = text; }
    public String getText() { return _text; }
  }
}

Returning a different object

There are some unusual cases where the configured bean is just a configuration object and you want to return a different bean. The bean can implement a method Object replaceObject() to return a different object. Called after the @PostConstruct methods.

See also


Copyright © 1998-2012 Caucho Technology, Inc. All rights reserved. Resin ® is a registered trademark. Quercustm, and Hessiantm are trademarks of Caucho Technology.

Cloud-optimized Resin Server is a Java EE certified Java Application Server, and Web Server, and Distributed Cache Server (Memcached).
Leading companies worldwide with demand for reliability and high performance web applications including SalesForce.com, CNET, DZone and many more are powered by Resin.

home company blog wiki docs 
app server web server 
health cloud java ee pro