<document>
<header>
<product>resin</product>
<title>Bean Configuration (Setter Injection)</title>
<description>
<p>Resin configures beans using bean-style (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>

<localtoc/>

<s1 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>

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

</s1>

<s1 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>

<s2 title="Type conversion">

<p>A setter can have a parameter that has a type other than
<code>String</code>. Resin will perform any type conversion
necessary, so you can use integers and doubles as well as strings.</p>

<example title="Bean-style configuration for type conversion">
&lt;init&gt;
  &lt;host&gt;www.gryffindor.com&lt;/host&gt;
  &lt;port&gt;80&lt;/port&gt;
&lt;/init&gt;
</example>

<example title="Bean-style java code for type conversion">
public class MyBean {
  private String _host;
  private int _port;

  public void setHost(String host) 
  {
    _host = host;
  }

  public void setPort(int port) 
  {
    _port = port;
  }
}
</example>

</s2>

<s2 title="Compatibility">

<p>Property configuration is very portable.  Any serious configuration system
will configure bean-style properties.</p>

</s2>

</s1>

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

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

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

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

<s2 title="Compatibility">

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

</s2>

</s1>

<s1 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>

</s1>

<s1 title="Validation and Assembly: @PostConstruct">

<p>Well-written resources will validate their configuration and may
perform additional assembly tasks.  Resin calls methods marked with the
@PostConstruct annotation after all the setter methods have been called.</p>

<example title="Bean-style @PostConstruct">
import javax.annotation.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);
  }
}
</example>

<s2 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">
import java.util.Locale;
import javax.annotation.PostConstruct;

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

<results>
500 Servlet Exception

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

<s1 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">
import javax.annotation.PostConstruct;
import javax.sql.*;

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

  ...
 
}
</example>
</s1>

<s1 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>

</s1>

<s1 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 @PostConstruct. </p>

</s1>

<s1 title="resin:type">

<s2 title="resin:type" type="defun">

<p>This special attribute can be used with all sub-beans to
instantiate a different bean class than the one defined in the parent
bean.</p>

<p>If a sub-bean is returned from method like <code>SubBean
createSubBean()</code> then <var>resin:type</var> cannot be used.  A
<code>void setParent(Object obj)</code> method in the sub-bean, which
is called before the other setters, provides an opportunity for the
sub-bean instance to know it's enclosing object.</p>

<p>
The <var>resin:</var> in <code>resin:type</code> is a namespace prefix automatically
mapped to <var>http://caucho.com/ns/resin</var>. You could use another namespace
prefix, for example if you defined
<var>xmlns:foo="http://caucho.com/ns/resin"</var>, you could use <code>foo:type</code>.
</p>

<example title="Bean-style configuration for using resin:type">
&lt;resource jndi-name="env/message"&gt;
  &lt;type&gt;example.MessageBean&lt;/type&gt;
  &lt;init&gt;
    &lt;message&gt;This is message 1&lt;/message&gt;
    &lt;message&gt;This is message 2&lt;/message&gt;
    &lt;message resin:type="example.CustomMessage"&gt;This is message 3&lt;/message&gt;
  &lt;/init&gt;
&lt;/resource&gt;
</example>

<example title="MessageBean.java">
package example;

import java.util.*;

public class MessageBean {
  List _msgs = new LinkedList();

  public void addMessage(Message msg) 
  { 
    _msgs.add(msg); 
    System.out.println("MessageBean.addMessage(): " + msg);
  }

  // this never get's called, because MessageBean has no parent
  public void setParent(Object obj) 
  { 
    System.out.println("MessageBean.setParent(): " + obj);
  }

}
</example>
<example title="Message.java">
package example;

public class Message {
  String _text;
  public void addText(String text) 
  { 
    _text = text; 
    System.out.println("Message.addText(): " + text);
  }

  public void setParent(Object obj) 
  { 
    System.out.println("Message.setParent(): " + obj);
  }

  public String toString()
  {
    return super.toString() + ": " + _text;
  }
}
</example>
<example title="Message.java">
package example;

public class CustomMessage extends Message {
  public void addText(String text) 
  { 
    _text = text; 
    System.out.println("CustomMessage.addText(): " + text);
  }

  public void setParent(Object obj) 
  { 
    System.out.println("CustomMessage.setParent(): " + obj);
  }
}
</example>

<results>
Message.setParent(): example.MessageBean@ffb35e
Message.addText(): This is message 1
MessageBean.addMessage(): example.Message@1591b4d: This is message 1
Message.setParent(): example.MessageBean@ffb35e
Message.addText(): This is message 2
MessageBean.addMessage(): example.Message@10f965e: This is message 2
CustomMessage.setParent(): example.MessageBean@ffb35e
CustomMessage.addText(): This is message 3
MessageBean.addMessage(): example.CustomMessage@12164ea: This is message 3
</results>

<p>In practice, it may make more sense to use <code>createSubBean</code> or
<code>addSubBean</code> to set a parent-child relationship for beans, instead
of <code>setParent</code>.  The possible issue with addSubBean is that
@PostConstruct methods are called before addSubBean.  The possible issue with
createSubBean is that it's
not possible to use a resin:type with createSubBean.  So the setParent is
useful when the @PostConstruct method needs the parent, and you need to use
resin:type.</p>

</s2>

</s1>

<s1 name="xml" title="Configuring beans from XML files">
<p>
The facilities provided by Resin make it very easy to 
read XML files.  Java classes that follow the java bean pattern 
are defined to match the schema of the xml file.
</p>

<example title="rss-example.xml">
&lt;rss version="0.91"&gt;
  &lt;channel&gt;
    &lt;title&gt;Hogwarts&lt;/title&gt; 
    &lt;link&gt;http://hogwarts.com&lt;/link&gt; 
    &lt;description&gt;Hogwart's News&lt;/description&gt;
    &lt;image&gt;
      &lt;title&gt;Hogwarts&lt;/title&gt; 
      &lt;url&gt;http://hogwarts.com/images/logo.gif&lt;/url&gt; 
      &lt;link&gt;http://hogwarts.com&lt;/link&gt; 
      &lt;width&gt;88&lt;/width&gt; 
      &lt;height&gt;31&lt;/height&gt; 
      &lt;description&gt;Hogwart's News&lt;/description&gt; 
    &lt;/image&gt;
    &lt;item&gt;
      &lt;title&gt;New Course Additions&lt;/title&gt;
      &lt;link&gt;http://hogwarts.com/news/00123.html&lt;/link&gt;
      &lt;description&gt;New course's are now available at Hogwart's.&lt;/description&gt;
    &lt;/item&gt;
    &lt;item&gt;
      &lt;title&gt;Dumbledore is back!&lt;/title&gt;
      &lt;link&gt;http://hogwarts.com/news/00122.html&lt;/link&gt;
      &lt;description&gt;
        After a short hiatus, Professor Dumbledore is back as 
        Headmaster of Hogwart's.
      &lt;/description&gt;
    &lt;/item&gt;
  &lt;/channel&gt;
&lt;/rss&gt;
</example>

<example title="example/rss/Rss.java">
package example.rss;

import java.util.ArrayList;

public class Rss {
  private String _version;
  private ArrayList&lt;Channel&gt; _channels = new ArrayList&lt;Channel&gt;;

  public void setVersion(String version)
  {
    _version = version;
  }

  public String getVersion()
  {
    return _version;
  }

  public void addChannel(Channel channel)
  {
    _channels.add(channel);
  }

  public ArrayList&lt;Channel&gt; getChannels()
  {
    return _channels;
  }
}

</example>

<example title="example/rss/Channel.java">
package example.rss;

import java.util.ArrayList;

public class Channel {
  private String _title;
  private String _link;
  private String _description;
  private String _language;
  private Image _image;
  private ArrayList&lt;Item&gt; _items = new ArrayList&lt;Item&gt;;

  public void setTitle(String title)
  {
    _title = title;
  }

  public String getTitle()
  {
    return _title;
  }

  public void setLink(String link)
  {
    _link = link;
  }

  public String getLink()
  {
    return _link;
  }

  public void setDescription(String description)
  {
    _description = description;
  }

  public String getDescription()
  {
    return _description;
  }

  public void setImage(Image image)
  {
    _image = image;
  }

  public Image getImage()
  {
    return _image;
  }

  public void addItem(Item item)
  {
    _items.add(item);
  }

  public ArrayList&lt;Items&gt; getItems()
  {
    return _items;
  }
}
</example>

<example title="example/rss/Image.java">
package example.rss;

public class Image {
  private String _title;
  private String _url;
  private String _link;
  private int _width;
  private String _height;
  private String _description;

  public void setTitle(String title)
  {
    _title = title;
  }

  public String getTitle()
  {
    return _title;
  }

  public void setLink(String link)
  {
    _link = link;
  }

  public String getLink()
  {
    return _link;
  }

  public void setWidth(int width)
  {
    _width = width;
  }

  public int getWidth()
  {
    return _width;
  }

  public void setHeigth(int height)
  {
    _height = height;
  }

  public int getHeight()
  {
    return _height;
  }

  public void setDescription(String description)
  {
    _description = description;
  }

  public String getDescription()
  {
    return _description;
  }
}
</example>

<example title="example/rss/Item.java">
package example.rss;

public class Item {
  private String _title;
  private String _link;
  private String _description;

  public void setTitle(String title)
  {
    _title = title;
  }

  public String getTitle()
  {
    return _title;
  }

  public void setLink(String link)
  {
    _link = link;
  }

  public String getLink()
  {
    return _link;
  }

  public void setDescription(String description)
  {
    _description = description;
  }

  public String getDescription()
  {
    return _description;
  }
}
</example>

<s2 title="NodeBuilder">

<p>
<a href="javadoc|com.caucho.config.NodeBuilder|"/> is used to configure 
beans from an xml file.
</p>

<example title="NodeBuilder constructs beans from rss-example.xml">
  import com.caucho.config.NodeBuilder;
  import com.caucho.vfs.Path;

  ...

  Rss rss = new Rss();
  NodeBuilder builder = new NodeBuilder();

  Path rssPath = new Path("WEB-INF/rss-example.xml");

  builder.configure(rss,rssPath);
</example>
</s2>

<s2 title="RNC validation">

<example title="RNC validation">
  import com.caucho.config.NodeBuilder;
  import com.caucho.vfs.Path;

  ...

  Rss rss = new Rss();
  NodeBuilder builder = new NodeBuilder();

  Path rssPath = new Path("WEB-INF/rss-example.xml");
  <b>Path schemaPath = new Path("WEB-INF/rss.rnc")</b>

  <b>builder.setCompactSchema(schemaPath);</b>

  builder.configure(rss,rssPath);
</example>

</s2>

<s2 name="import" title="resin:import">
<p>
resin:import is used to read configuration information from another file.
</p>

<example title="rss-example.xml">
&lt;rss version="0.91"&gt;
 &lt;resin:import&gt;
   &lt;fileset dir="channels/"&gt;
     &lt;include name="*.xml"/&gt;
   &lt;/fileset&gt;
  &lt;/resin:import&gt;
</example>

<example title="channels/hogwarts.xml">
&lt;channel&gt;
  &lt;title&gt;Hogwarts&lt;/title&gt; 
  &lt;link&gt;http://hogwarts.com&lt;/link&gt; 
  &lt;description&gt;Hogwart's News&lt;/description&gt;
  &lt;image&gt;
    &lt;title&gt;Hogwarts&lt;/title&gt; 
    &lt;url&gt;http://hogwarts.com/images/logo.gif&lt;/url&gt; 
    &lt;link&gt;http://hogwarts.com&lt;/link&gt; 
    &lt;width&gt;88&lt;/width&gt; 
    &lt;height&gt;31&lt;/height&gt; 
    &lt;description&gt;Hogwart's News&lt;/description&gt; 
  &lt;/image&gt;
  &lt;item&gt;
    &lt;title&gt;New Course Additions&lt;/title&gt;
    &lt;link&gt;http://hogwarts.com/news/00123.html&lt;/link&gt;
    &lt;description&gt;New course's are now available at Hogwart's.&lt;/description&gt;
  &lt;/item&gt;
  &lt;item&gt;
    &lt;title&gt;Dumbledore is back!&lt;/title&gt;
    &lt;link&gt;http://hogwarts.com/news/00122.html&lt;/link&gt;
    &lt;description&gt;
      After a short hiatus, Professor Dumbledore is back as 
      Headmaster of Hogwart's.
    &lt;/description&gt;
  &lt;/item&gt;
&lt;/channel&gt;
</example>

<s3 title="See also">
<ul>
<li><a href="config-control.xtp#resin:import">resin:import</a>
</li><li><a href="../examples/ioc-injection/index.xtp">Dependency Injection Tutorial</a>
</li></ul>
</s3>
</s2> <!-- import -->

</s1> <!-- xml -->

</body>
</document>
