<document>
<header>
<title>Setter Injection Bean Patterns</title>
<description>
<p>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.</p>

<p>Resin's configuration follows the <em>Assembly Line</em>
or <em>Dependency Injection</em> pattern.</p>

</description>
</header>
<body>

<summary objsummary='none'/>

<section title="Overview">

<p>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.</p>

<p>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.</p>

<p><figure src="assembler-eg1.gif"/></p>

</section>

<section title="Property Configuration: setXXX">

<p>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.</p>


<p>Each configuration parameter <var>foo</var> has a corresponding setter method
<code>setFoo</code> with a single argument for the value.  Resin
looks at the class using Java's reflection to find the <code>setFoo</code>
method.</p>
        
<example title="Bean-style configuration for a single value setter">
&lt;init&gt;
  &lt;greeting&gt;Hello, World!&lt;/greeting&gt;
  &lt;another-greeting&gt;Hello, Mom!&lt;/another-greeting&gt;
&lt;/init&gt;
</example>

<example title="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;
  }
}
</example>

</section>

<section title="Setter Injection: setXXX">

<p>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.</p>

<p>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.</p>

<example title="Configuration for Setter Injection">
&lt;init>
  &lt;data-source>\${jndi:lookup("jdbc/test")}&lt;data-source>
&lt;/init>
</example>

<example title="Setter Injection for a DataSource">
public class MyBean {
  private DataSource _dataSource;

  public void setDataSource(DataSource ds)
  {
    _dataSource = ds;
  }
}
</example>

<section title="Compatibility">

<p>Setter injection is portable to containers which
support dependency injection.</p>

</section>

</section>

<section title="Container Properties: addXXX">

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

<p>A setter method <code>addFoo</code> allows multiple values to be
specified from the configuration.</p>

<example title="Bean-style configuration for setting multiple values">
&lt;init&gt;
  &lt;greeting&gt;Hello, World!&lt;/greeting&gt;
  &lt;greeting&gt;Hello, Mom!&lt;/greeting&gt;
&lt;/init&gt;
</example>

<example title="Bean-style java code for setting multiple values">
public class MyBean {
  private LinkedList _greetings = new LinkedList();

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

}
</example>

</section>

<section title="Validation and Assembly: init()">

<p>Well-written resources will validate their configuration and may
perform additional assembly tasks.  Resin calls <code>init()</code> method
after all the setter methods have been called.</p>

<example title="Bean-style init()">
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;
  }

  public void init()
  {
    locale = new Locale(language, country);
  }
}
</example>

<section title="Validation Exceptions">
<p>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.</p>

<example title="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;
  }

  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);
  }
}
</example>

<results>
500 Servlet Exception

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

<section title="Nested Beans: createXXX">

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

<example title="Bean-style configuration for sub-beans">
&lt;init&gt;
  &lt;table&gt;
    &lt;name&gt;Foo&lt;/name&gt;
    &lt;timestamp-field&gt;tstamp&lt;/timestamp-field&gt;
  &lt;/table&gt;

  &lt;table name="Bar" timestamp-field="ts"/&gt;
&lt;/init&gt;
</example>

<example title="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;
    }

    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) {
        }
      }
    }
  }

  ...
 
}
</example>
</section>

<section title="Setting with the body text">
<p>The <code>addText()</code> method will capture the body of the tag
for a bean setter.</p>

<example title="Bean-style configuration for setting with the body text">
&lt;init&gt;
  &lt;message&gt;This is the message&lt;/message&gt;
&lt;/init&gt;
</example>

<example title="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; }
  }
}
</example>

</section>

<section title="Returning a different object">

<p>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 <code>Object replaceObject()</code> to return a
different object. Called after the init(). </p>

</section>

<section title="See also">
<ul>
<li><a href="doc|config|control#resin:import">resin:import</a>
<li><a href="doc|resource|tutorial/injection/index.xtp">Dependency Injection Tutorial</a>
</ul>
</section> <!-- import -->

</body>
</document>
