Resin 4 IoC Examples

From Resin 4.0 Wiki

Revision as of 00:00, 16 June 2012 by Rick (Talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Cookbook-48.png

Construction-48.png

Contents

Inversion of Control (IoC) Tutorials

Application configuration files using a WebBeans object

Applications often need to read, and possibly write, configuration files. An excellent way to accomplish this is to implement a custom singleton, 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. An object of type AppConfig is obtained with a javax.enterprise.inject.Current injection. It is used to open files relative to the base directory.

Files in this tutorial

File Description
WEB-INF/web.xml Configure the AppConfig object as a resource
WEB-INF/classes/example/AppConfig.java The AppConfig object provides input and output streams to configuration files
WEB-INF/classes/example/TestServlet.java A simple example usage of AppConfig that reads and writes a file
index.jsp The starting page for the tutorial

The java code for a custom Singleton

A custom singleton is a standard java-bean (see [doc|resin-ioc.xtp Resin-IoC]). 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". The @PostConstruct annotation tells Resin to call the init() method after all of the setters have been called.

AppConfig.java

import javax.annotations.PostConstruct;

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

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

  ...

Configuring the custom singleton

Configuration of the singleton is done with the <example:AppConfig> 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.

The EL configuration variable webApp.root is used.

Configuring the AppConfig singleton in resin-web.xml

<web-app xmlns="http://caucho.com/ns/resin">

  <example:AppConfig xmlns:example="urn:java:example">
    <config-files-location>${webApp.root}/WEB-INF/config</config-files-location>
  </example:AppConfig>

</web-app>


Obtaining and using the object

An instance of the object is retrieved in the application using dependency injection. In this example servlet, we'll use field-based injection, marked by the @javax.enterprise.inject.Current annotation. We could also use method injection.

Resin will look in the WebBeans registry for the AppConfig object that we've configured in the resin.conf, and inject it into the servlet. Resin will report any errors in looking up the AppConfig object, e.g. if it's not configured in the resin.conf or if you've configured multiple AppConfig instances.

Obtaining the AppConfig object

import javax.enterprise.inject.Current;

public class TestServlet extends GenericServlet {
  @Current AppConfig _appConfig;
}

_appConfig is used to open the configuration files for reading and writing.

Using the AppConfig object

...

    InputStream is = _appConfig.openConfigFileRead(inputFile);

...

    OutputStream os = _appConfig.openConfigFileWrite(outputFile);

...


Variation - Hiding the configuration file with getters

The example in this tutorial is easily modified to allow the hiding of the configuration file behind get methods of the bean. Implementing getters on the configuration bean abstracts the configuration information, protecting code which uses the configuration information from implementation details of how the configuration information is read and stored.

Hiding the configuration file with getters

package example;

import java.util.*;
import java.io.*;

public class AppConfig {
  private final static String DEFAULT_PROPERTIES = "example/AppConfig.properties";

  private String _configFile;
  private Properties _properties;


  /**
   * Optionally set the name of a file that provides properties that override
   * the defaults.  The defaults are obtained from a file in the classpath 
   * named 'example/AppConfig.properties'
   *
   * For example, the file containing default properties might be in 
   * WEB-INF/classes/example/AppConfig.properties,
   * or if AppConfig.class is in a jar, the AppConfig.properties 
   * could be in the jar file alongside the AppConfig.class file.
   *
   * AppConfig.properties contains values placed there by the developer.
   * The <config-file> is used to indicate a file that specifies properties
   * that override the defaults, perhaps properties that change depending 
   * on the deployment environment.
   */
  public void setConfigFile(String configFile)
    throws Exception
  {
    _configFile = configFile;
  }

  @PostConstruct
  public void init()
    throws Exception
  {
    InputStream is = null;

    if (_configFile != null) {
      // the properties in _configFile override the defaults
      is = new FileInputStream(_configFile);

      _properties = new Properties(defaults);
      _properties.load(is);
    }
    else {
      // try to find a default configuration file in the classpath
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      is = loader.getResourceAsStream(DEFAULT_PROPERTIES);

      if (is != null)
        _properties = new Properties();
        _properties.load(is);
      }
      else {
        // throw an exception here to make the defaults required
        throw new FileNotFoundException(DEFAULT_PROPERTIES);
      }
    } 
  }

  public String getFoo()
  { 
    return _properties.getProperty("foo");
  }

  public String getBar()
  { 
    return _properties.getProperty("bar");
  }
}

<example>

<web-app xmlns="http://caucho.com/ns/resin">

<example:AppConfig xmlns:example="urn:java:example"/>

</web-app>

or

<web-app xmlns="http://caucho.com/ns/resin">

<example:AppConfig xmlns:example="urn:java:example">
   <config-file>${webApp.root}/WEB-INF/AppConfig-override.properties</config-file>
</example:AppConfig>

</web-app> </example>

==

package example;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.enterprise.inject.Current;

import java.io.*;
import java.util.*;

public class TestServlet extends HttpServlet {
  @Current AppConfig _appConfig;

  ...

  String foo = _appConfig.getFoo();
  String bar = _appConfig.getBar();

  ...

}


Availability of AppConfig from different web-apps

The availability of AppConfig to different web-apps depends upon the context that the <example:AppConfig> configuration is placed within.

If the configuration is placed as a child of <web-app>, then that instance of AppConfig is available only to that web-app.

WEB-INF/resin-web.xml local to web-app

<web-app xmlns="http://caucho.com/ns/resin">

 <example:AppConfig xmlns:example="urn:java:example"/>

</web-app>

If it is placed as a child of <host>, that instance of AppConfig is available to all web-apps within the host.

shared host configuration in resin.conf

<resin xmlns="http://caucho.com/ns/resin">
<cluster id="">

  <host id="">

    <example:AppConfig xmlns:example="urn:java:example"/>

    ...

  </host>

</cluster>
</resin>

If the <example:AppConfig> is placed as a child of <cluster>, that instance of AppConfig is available to all web-apps within all hosts within that cluster.

shared cluster configuration in resin.conf

<resin xmlns="http://caucho.com/ns/resin">
<cluster id="">

   <example:AppConfig xmlns:example="urn:java:example"/>

   <host id="">
      ...
   </host id="">
  ...
</cluster>
</resin>

In the case of <cluster> or <host>, the example.AppConfig class needs to be available in the classpath. The easiest way to accomplish that is to place a jar with that class in $RESIN_HOME/lib, or you can use an explicit <class-loader> tag.


A Simple Resource Bean

Resources are beans configured in the resin.conf or resin-web.xml and stored in the WebBeans registry. The tutorial shows the configuration of a trivial bean as a resource and using it from a JSP file.

Overview

A resource in Resin is any bean configured in the resin.conf or resin-web.xml. Resources are stored in the WebBeans registry. Because resources can be any Java class conforming to the bean configuration patterns, resources provide a flexible configuration.

There is also more documentation for [../../admin/candi.xtp Java Injection].

Some typical resources include:

  • Databases
  • JMS connections
  • EJB stateful and stateless session beans
  • JCA resources

Because resources are configured in the resin.conf/resin-web.xml and are created before any servlets start, they are very convenient for globally available beans, even allowing for more complex configuration beans extending the idea of <env-entry> (which stored simple Strings or Integers in JNDI.)


The TestResource bean

The TestResource bean is almost as simple as possible. It has a single String configuration parameter and does nothing but print its value using toString().

TestResource.java

package test;

public class TestResource {
  private String _value = "default";

  public void setValue(String value)
  {
    _value = value;
  }

  public String toString()
  {
    return "TestResource[" + _value + "]";
  }
}

In other words, you have lots of flexibility of things to configure as resources.


resin-web.xml configuration

The resin-web.xml (or resin.conf) configures the resource with the <test:TestResource> tag. The resource is created and stored in the environment where it is defined. So a resource configured in the <host> will be available for all web-apps in that host and a resource configured in a <web-app> will only be available for that <web-app>.

resin-web.xml

<web-app xmlns="http://caucho.com/ns/resin">

  <test:TestResource xmlns:test="urn:java:test">
    <test:value>An Example Resource</test:value>
  </test:TestResource>

</web-app>
tag description
test:TestResource The classname of the resource bean
Named the optional Java Injection name of the resource for PHP
value The example bean's setValue parameter.


Using the resource from PHP

Your PHP scripts can use any Java Injection resource by using the java_bean() method. The method will return the named resource.

test.php

<php?

$resource = java_bean("testResource");

echo "PHP resource: " . $resource . "\n";

?>


Using the resource from JSP

JSP pages can also use WebBeans resource in the JSP expression language.

test.jsp


JSP resource: ${testResource}


Using the resource from a Servlet

The example uses a servlet to demonstrate the resource, but any injectable class could use @javax.inject.Inject to look up and use the resource. Because resources are stored globally in Java Injection, they can avoid the complexity of passing objects around or storing in the servlet context.

If you save the resource, it's important that the saved field is reloaded when the web-app restarts. The resource has the same lifetime as its environment: web-app, host or cluster. When that environment closes, the resource is no longer valid and must be discarded. In particular, it is important to store any resource in an object's field, not in a static field or static hashtable.

TestServlet.java

package test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import javax.inject.Inject;

public class TestServlet extends HttpServlet {
  @Inject private TestResource _resource;
  
  public void doGet(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException
  {
    PrintWriter out = res.getWriter();

    out.println("Resource: " + _resource);
  }
}

results

Resource: TestResource[An example resource]


CanDI (Java Injection) Pattern Tutorial

Four of the primary Java Injection patterns.

Overview

The four main CanDI patterns share a common goal: improve code with a declarative injection style. When Java classes cleanly describe their dependencies, their lifecycles, and their exports, they are self-documenting. You can read the classes and understand how they will behave, i.e. you don't need to read the code side-by-side with XML configuration to understand the system's behavior.

The custom, typesafe binding annotations are key to CanDI's self-documentation, because injection points clearly describe the resources or services they expect with adjective-oriented annotations. Because the annotations are true Java classes, they are documented in JavaDoc and verified by the compiler. The small number of meaningful adjectives means they don't impose a significant coding burden, and are well worth the small extra development time.

<deftable title="CanDI Application Patterns"> <tr>

 <th>Pattern</th>
 <th>Description</th>

</tr> <tr>

 <td>Service Pattern</td>
 <td>Organize the application as a collection of services.</td>

</tr> <tr>

 <td>Resource Configuration Pattern</td>
 <td>Bind and resources with declarative annotations and configure with XML.</td>

</tr> <tr>

 <td>Startup Pattern</td>
 <td>Use @Startup beans to initialize application state.</td>

</tr> <tr>

 <td>Plugin/Extension Pattern</td>
 <td>Discover plugin/extension classes for a service.</td>

</tr> </table>

This tutorial describes four main CanDI design patterns: services, resources, startup and extensions. Services center an application's design by encapsulating management and data. Resources are the configurable interface between the user and the application. Startup initializes the application. And extensions allow sophisticated applications to tailor their behavior to the user's needs.

Tutorial Architecture

<figure src="ioc-binding.png" alt="(@Blue BlueResourceBean, @Red RedResourceBean) -> (SetServlet @Inject MyService, GetServlet @Inject MyService) <- MyServiceBean" />

Since the purpose of the service pattern is encapsulating state and managment for multiple clients, the tutorial shows a single service used by multiple servlets and by PHP and JSP scripts. Services are typically singletons in the application and use @Inject to mark the binding.

The resource pattern configures a driver class and properties in XML for an application resource. The resource tutorial uses MyResource as a general resource API, like DataSource or EntityManager, and application specific bindings @Red and @Blue. Because resource APIs are general, they need an application-specific description to document their purpose in the code. Binding annotations are simple, clear adjectives, and typically only a small number are needed. The driver classes like BlueResourceBean are typically selected and configured in an XML, like selecting and configuring a database.

Startup initialization is needed by most applications, and can use the CanDI startup pattern to document the startup classes and avoid unnecessary XML. Because CanDI discovers beans through classpath scanning, you can create startup beans with just a @Startup annotation and a @PostConstruct method.

A plugin or extension capability can improve the flexibility of many applications, even if designed for internal use. The plugin pattern uses CanDI's discovery process for the plugin capability without requiring a new infrastructure. The tutorial reuses the MyResource API as a plugin API and grab all implementations using the CanDI Instance interface and the @Any annotation.


Java Injection API

The most important CanDI classes are just three annotations: @Inject, @Qualifier and @Singleton, because many applications will primarily use the service and resource patterns. By using these three annotations effectively, you can improve the readability and maintainability of your application's services and resources.

<deftable title="Service and Resource Pattern CanDI classes" > <tr>

<th>Annotation/Class</th>
<th>Description</th>

</tr> <tr>

 <td>@Singleton</td>
 <td>scope annotation marking the service as a singleton</td>

</tr> <tr>

 <td>@Qualifier</td>
 <td>descriptive application bindings are marked with this meta-annotation</td>

</tr> <tr>

 <td>@Inject</td>
 <td>Default binding for unique beans (service pattern).</td>

</tr> </table>

Applications which provide scripting access to services or resources will use the @Named annotation to provide a scripting name for the beans.

<deftable title="Scripting Support CanDI classes" > <tr>

<th>Annotation/Class</th>
<th>Description</th>

</tr> <tr>

 <td>Named</td>
 <td>Scriping and JSP/JSF EL access to CanDI beans (service pattern)</td>

</tr> </table>

The startup pattern uses two additional annotations, @Startup to mark the bean as needing creation on container start, and @PostConstruct marking a method to be initialized.

<deftable title="Startup Pattern CanDI classes" > <tr>

<th>Annotation/Class</th>
<th>Description</th>

</tr> <tr>

 <td>@Startup</td>
 <td>Starts a bean when the container starts.</td>

</tr> <tr>

 <td>@PostConstruct</td>
 <td>Calls an initialization method the bean is created.</td>

</tr> </table>

A plugin or extension architecture uses two additional CanDI classes to easily find plugins discovered during CanDI's classpath scanning. Instance<T> provides an iterator over all the discovered and configured beans, and @Any selects all beans independent of their @Qualifier.

<deftable title="Plugin/Extension Pattern CanDI classes" > <tr>

<th>Annotation/Class</th>
<th>Description</th>

</tr> <tr>

 <td>Instance<T></td>
 <td>Programmatic access to all implementations of an interface.</td>

</tr> <tr>

 <td>@Any</td>
 <td>Selects all matching beans for an interface.</td>

</tr> </table>


Files in this tutorial" web-only='true

<deftable title="Files: Service Pattern"> <tr>

 <th>File</th>
 <th>Description</th>

</tr> <tr>

 <td>WEB-INF/classes/example/MyServiceBean.java</td>
 <td>Implementation of the MyService service bean.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/MyService.java</td>
 <td>Service interface for the resource pattern.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/GetServlet.java</td>
 <td>Demonstration of four CanDI patterns.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/SetServlet.java</td>
 <td>Demonstration of four CanDI patterns.</td>

</tr> <tr>

 <td>test.php</td>
 <td>PHP using a service with java_bean() and the @Named annotation.</td>

</tr> <tr>

 <td>test.jsp</td>
 <td>JSP using a service with java_bean() and the @Named annotation.</td>

</tr> <tr>

 <td>WEB-INF/beans.xml</td>
 <td>CanDI beans.xml triggering classpath scanning.</td>

</tr> </table>

<deftable title="Files: Configuration and Plugin Pattern"> <tr>

 <th>File</th>
 <th>Description</th>

</tr> <tr>

 <td>WEB-INF/resin-web.xml</td>
 <td>Configuration of custom resources.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/Blue.java</td>
 <td>Binding Type annotation for the @Blue resource.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/BlueResourceBean.java</td>
 <td>Implementation of the @Blue bean.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/MyResource.java</td>
 <td>Resource interface for the resource pattern.</td>

</tr> <tr>

 <td>WEB-INF/classes/example/SetServlet.java</td>
 <td>Demonstration of four CanDI patterns.</td>

</tr> </table>

<deftable title="Files: Startup Pattern"> <tr>

 <th>File</th>
 <th>Description</th>

</tr> <tr>

 <td>WEB-INF/classes/example/MyStartupBean.java</td>
 <td>Startup bean to configure other resources on web-app initialization.</td>

</tr> </table>

Service Pattern

Because services are often unique in an application, the service interface is generally enough to uniquely identify the service. In CanDI, the @Inject annotation injects a unique service to a client class. A declarative style applies to both the service declaration and the service use, by annotating the service scope as @Singleton, and annotating the client injection as @Inject. By describing the function on the class itself, CanDI's annotations improve the readability and maintainability of service classes.

Example: GetServlet.java

package example;

import javax.inject.Inject;
...

public class GetServlet extends HttpServlet {
  private @Inject MyService _service;

  ...
}

Users of the service will access it through an interface like MyService. The implementation will be a concrete class like MyServiceBean. The interface API in CanDI is a plain Java interface with no CanDI-specific annotations or references.

Example: MyService.java

package example;

public interface MyService {
  public void setMessage(String message);
  
  public String getMessage();
}

All the information relevant to the class deployment is on the class itself, because the service implementation is discovered through CanDI's classpath scanning. In other words, The service's deployment is self-documenting. Since services are generally singletons, they will typically have the @Singleton annotation. Other annotations are optional and describe the service registration or behavior. For example, the tutorial uses the @Named tag, because the test.jsp and test.php need a named reference.

Scripting beans use the @Named annotation on a CanDI bean for integration with the JSP EL expression language and with PHP. Nonscripting beans do not declare a @Named annotation because CanDI uses the service type and binding annotations for matching.

Example: MyServiceBean.java

package example;

import javax.inject.Singleton;
import javax.inject.Named;
import javax.enterprise.inject.Default;

@Singleton
@Named("myService")
@Default
public class MyServiceBean implements MyService {
  private String _message = "default";
  
  public void setMessage(String message)
  {
    _message = message;
  }
  
  public String getMessage()
  {
    return _message;
  }
}

Using Services from PHP and JSP

CanDI is designed to integrate closely with scripting languages like PHP and JSP. The scripting languages locate a CanDI service or resource using a string, because scripting lacks the strong typing needed for full dependency injection. As mentioned above, the name of a CanDI service is declared by the @Named anntation on the bean itself. The PHP or JSP code will use the name to obtain a reference to the bean. For PHP, the function call is java_bean as follows:

Example: test.php

<?php

$myService = java_bean("myService");

echo $myService->getMessage();

?>

While PHP has a function access to the CanDI service or resource, JSP and JSF grab the CanDI bean with using the JSP expression language. Any CanDI bean with a @Named annotation automatically becomes available to EL expressions as follows:

Example: test.jsp

message: ${myService.message}


Resource XML Configuration Pattern

Resources like databases, and queues fit multiple roles in an application and need configuration and description beyond their generic DataSource and BlockingQueue APIs. While services are generally unique and can use the @Inject qualifier, resources will generally create custom @Qualifier annotations to identify and document the resource.

CanDI encourages a small number of binding annotations used as adjectives to describe resources. A typical medium application like a mail list manager might use half a dozen custom binding adjectives, and may need fewer or more depending on the number of unique resources. Each database, queue, mail, and JPA EntityManager will generally have a unique name. If users need customization and configuration of internal resources, you may need additional binding types. If the application has a single database, it might only have one binding annotation, or might even use @Inject.

The purpose of the binding annotation is to self-document the resource in the client code. If the application uses @ShoppingCart database and a @ProductCatalog database, the client code will bind by their description. The code declares its dependencies in a readable way, and lets CanDI and the configuration provide the resource it needs.

The tutorial has @Red resource, configured in XML because the user might need to customize the configuration. The resource client, SetServlet, uses the adjective annotation in the field declaration as follows:

Example: SetServlet.java

public class SetServlet extends HttpServlet {
  private @Red MyResource _red;
  private @Blue MyResource _blue;

  ...
}

The XML is short and meaningful, because it's only required for customization, not for wiring and binding. Databases and JMS queues will need to configure the database driver and add the binding adjective. Applications resources can also be configured in XML if exposing the configuration is useful to your users, but unique internal classes like most services will stay out of the XML. In our example, we let the users configure the data field of the resource and let them choose the implementation class.

The XML configuration for a bean needs three pieces of data: the driver class, the descriptive binding annotation, and any customization data. Because the driver is the most important, CanDI uses the class as the XML tag and uses the package as the XML namespace. While scanning the XML, the driver class is top and prominent, reflecting its importance. In the example, <example:BlueResourceBean> is the driver class.

Example: BlueResourceBean instance configuration

<example:BlueResourceBean xmlns:example="urn:java:example">
  ...
</example:BlueResourceBean>

In CanDI, the binding annotation is also an XML tag, represented by its classname and package. In CanDI, classes and annotations get XML tags with camel-case names matching the classname, and XML for properties are lower case. The case distinguishes annotations from properties in the XML, improving XML readability.

Example: @Blue annotation configuration

<example:Blue xmlns:example="urn:java:example"/>

Properties of a resource use the standard beans-style names, so <example:data> sets the bean's setData property. CanDI converts the XML string value to the property's actual value. In this case, the conversion is trivial, but CanDI can convert to integers, doubles, enumerations, classes, URLs, etc. Beans have all the configuration capabilities as Resin beans in the resin.xml and resin-web.xml, because Resin uses CanDI for its own internal configuration.

Example: resin-web.xml

<web-app xmlns="http://caucho.com/ns/resin"
	 xmlns:example="urn:java:example">

  <example:BlueResourceBean>
    <example:Blue/>
    <example:data>blue resource</example:data>
  </example:BlueResourceBean>

  <example:RedResourceBean>
    <example:Red/>
    <example:data>red resource</example:data>
  </example:RedResourceBean>

</web-app>  

Binding types should generally be descriptive adjectives, so it can describe the injection clearly. Anyone reading code should understand immediately which resource it's using. The tutorial's @Blue binding annotation itself is a normal Java annotation marked by a CanDI @Qualifier annotation. Because of its importance and because there are only a small number of custom annotations, it's important to spend time choosing a good descriptive name for the annotation.

Example: Blue.java

package example;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import javax.inject.Qualifier;

@Qualifier
@Documented
@Target({TYPE, METHOD, FIELD, PARAMETER})
@Retention(RUNTIME)
public @interface Blue {
}

The resource implementation itself is straightforward. When the resource is a singleton, it will need a @Singleton annotation, just like a service. By default, CanDI will inject a new instance of the bean at every injection point.

Example: BlueResourceBean.java

package example;

public class BlueResourceBean {
  private String _data;
  
  public void setData(String data)
  {
    _data = data;
  }
}


Startup Pattern

The @Startup annotation marks a bean as initializing on server startup. Because the startup bean is discovered through classpath scanning like the other beans, the initialization is controlled by the startup class itself. In other words, looking at the startup class is sufficient, because it doesn't rely on XML for startup. The startup bean uses the @PostConstruct annotation on an initialization method to start initialization code.

Example: MyStartupBean.java

package example;

import javax.annotation.PostConstruct;
import javax.ejb.Startup;
import javax.inject.Inject;

@Startup
public class MyStartupBean {
  private @Inject MyService _service;

  @PostConstruct
  public void init()
  {
    _service.setMessage(this + ": initial value");
  }
}


Plugin/Extension Pattern

A plugin or extension architecture can make an application more flexible and configurable. For example, a filtering system, or blueprints or custom actions can add significant power to an application. The plugin pattern uses CanDI's discovery system to find all implementations of the plugin interface. The Instance iterator together with the special @Any binding annotation gives all implementations of a resource.

The CanDI Instance interface has two uses: return a unique instance programmatically with the get() method, and list all instances for a plugin capability. Since Instance implements the JDK's Iterable interface, you can use it in a for loop. Each returned instance obeys the standard CanDI scoping rules, either returning the single value for @Singleton singletons, or creating a new instance for the default.

The @Any annotation works with Instance to select all values. Because bindings default to the @Inject binding type, we need to override the default to get all instances.

Example: GetServlet.java

package example;

import javax.inject.Inject;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Instance;
...

public class GetServlet extends HttpServlet {
  @Inject @Any Instance<MyResource> _resources;

  public void service(HttpServletRequest request,
                      HttpServletResponse response)
    throws IOException, ServletException		       
  {
    PrintWriter out = response.getWriter();

    for (MyResource resource : _resources) {
      out.println("resource: " + resource);
    }
  }
}


Dependency Injection for Resources

The Dependency Injection pattern simplifies application code, and increases configuration flexibility by deferring component configuration and assembly to the container. Resin calls setters on the configured objects to assemble the resource dependencies.


Files in this tutorial

File Description
WEB-INF/resin-web.xml Configures the movie application
WEB-INF/classes/example/Movie.java The movie bean.
WEB-INF/classes/example/MovieFinder.java The MovieFinder interface
WEB-INF/classes/example/MovieFinderImpl.java A MovieFinder implementation
WEB-INF/classes/example/MovieLister.java The MovieLister to be configured with the finder implementation
WEB-INF/classes/example/MovieServlet.java The MovieServlet to be configured with the finder implementation
WEB-INF/classes/META-INF/web-beans.xml web-beans.xml marks the directory as containing components.


Dependency Injection

Dependency injection is a term used to describe a separation between the implementation of an object and the construction of an object it depends on, and the ability for a container like Resin to resolve the dependency.

Since the container instantiates and assembles the dependencies, the code is simpler and the configuration is more flexible. It's easy to substitute test implementations as the dependent resources, for example.

The MovieFinder example for this tutorial comes from Martin Fowler's <a href="http://www.martinfowler.com/articles/injection.html">Dependency Injection</a> article.

More details on Resin's configuration is available at the [doc|ioc-bean.xtp bean-style configuration] page.

Configuration as Assembly Line

<figure src="assembler-eg1.gif" alt="Assembler(Resin),Registry(JNDI) -> (MovieLocator,MovieFinderImpl)" />

The Dependency Injector pattern could also be called the Assembly pattern because it resembles an assembly line making cars.

  • Parts are interchangable components like wheels. The parts might also be assembled like an engine in a car.
  • Parts are attached to the Chassis like a car's frame receiving an engine.
  • The Registry is holds partially-completed parts like a factory conveyor belt.
  • The Assembler provides the Registry and assembles the Chassis and Parts into a completed resource.

Some important points:

  • The application code (Chassis and Parts) is independent of the Assembler.
  • Parts are interchangeable.
  • The code needs to select an assembly pattern, e.g. Setter Injection.

Because the Assembler is independent of the code, a project could change the Assembler from Spring to Resin with no code changes. So using the Assembler/Dependency Injection pattern reduces dependencies on the framework. Only the configuration changes when changing Assemblers, not the code.

While testing, the test case or the harness plays the Assembler role, simplifying the test suite and ensuring that the code under test is the production code. A test can create a test implementation of the Part, e.g. TestMovieFinder, for testing.

In some cases, the application code can provide its own assemble() method for situations where the container is incapabile of assembling the components. For example, the MovieServlet could create an assemble() method that grabbed the MovieLocator from JNDI.


Code for the Dependency Injection pattern

The only code specific to the setter-based injection pattern is the addition of a setter method for the dependent resource. In many application, that setter will already be written, so no additional code would be required.

Either an interface or a class can be used for the dependent resource, depending on the application's architecture. This example uses both: the MovieLister uses a dependent MovieFinder interface, and the MovieServlet uses the dependent MovieListener class.

Example: finder injection

import javax.inject.Inject;

public class MovieListener {
  @Inject private MovieFinder _finder;

  ...
}


Configuration

Example: Configuring the MovieFinder Service

<web-app xmlns="http://caucho.com/ns/resin">

<example:MovieFinderImpl xmlns:example="urn:java:example">
  <movie director="Jackson" title="Fellowship of the Ring"/>
  <movie director="Jackson" title="The Two Towers"/>

  <movie director="Lucas" title="Star Wars"/>

  <movie director="Gilliam" title="Brazil"/>
</example:MovieFinderImpl>

</web-app>


Java Injection for Servlets

The Dependency Injection pattern is just as useful for servlet configuration as it is for resources. This example makes the MovieLister a parameter of the servlet. The resin-web.xml will configure the servlet with the appropriate MovieLister

The advantages of using dependency injection for the servlet are the same as for the resource:

  • The servlet code becomes simpler.
  • The servlet is no longer dependent on JNDI.
  • The servlet is more easily testable by configuring it with test versions of the MovieListener.

Configuring the MovieServlet

import javax.inject.Inject;

public class MovieServlet extends HttpServlet {
  // Inject the MovieLister service
  @Inject private MovieLister _movieLister;

  ...
}


See also

  • [doc|resin-ioc.xtp Resin/WebBeans Dependency Injection]
  • [../db-jdbc-ioc/index.xtp Servlet DataSource Configuration]
  • [../hessian-ioc/index.xtp Hessian with Dependency Injection]


PeriodicTask Tutorial

This tutorial demonstrates the creation of a PeriodicTask that performs a task at intervals and collects statistics on it's performance. An administration interface to the task is provided, and while the task is active the user is shown a "temporarily unavailable" page.

The code for this tutorial provides a full featured example that can be used as a cut-and-paste source for solving real problems. The PeriodicTask keeps detailed statistics, an administration interface is provided with a servlet, and the task can be executed either manually or automatically at timed intervals.


Files in this tutorial

File Description
WEB-INF/classes/example/PeriodicTask.java The implementation of the class that performs the task
WEB-INF/classes/example/PeriodicTaskMBean.java The Jmx MBean interface to the class that performs the task
WEB-INF/classes/example/PeriodicTaskServlet.java An administrators view of the PeriodicTask.
WEB-INF/classes/example/PeriodicTaskFilter.java A filter that responds with a "temporarily unavailable" page when the
       task is running.
WEB-INF/web.xml web-app configuration
index.jsp A page representative of any page in the application.
unavailable.jsp A page to show when the web application is unavailable because
       the task is active.

bean Configuration

The <a config-tag="bean"/> tag is used to configure an instance of PeriodicTask, and store it with the Resin-IoC/WebBeans registry.

PeriodicTask is implemented as a regular Java object that follows the JavaBeans convention for setters and getters. The configuration of the object occurs in the web.xml, using Resin's <a href="doc|resin-ioc.xtp">Bean-style initialization</a>.

WEB-INF/resin-web.xml" language="java

<web-app xmlns="http://caucho.com/ns/resin">

  <bean class="example.PeriodicTask">
    <init>
      <estimated-average-time>5</estimated-average-time>
    </init>
  </bean>

</web-app>

If only this step were performed, the object would sit in the JVM memory, performing no function. The rest of this tutorial details various ways that the PeriodicTask can be utilized.


Using PeriodicTask for real work

This tutorial performs no real work in it's task, it sleeps for 10 seconds to imitate a task that takes ten seconds. The code can be used without modification to perform real tasks for your web application. All of the statistics gathering and other functionality is available for the derived class.

Extend PeriodicTask

The following example extends PeriodicTask to create a task that vacuum's a postgress database.

WEB-INF/classes/example/VacuumTask.java

package example;

import java.util.logging.Level;
import java.util.logging.Logger;

import java.sql.*;
import javax.sql.*;

public class VacuumTask extends PeriodicTask {
  static protected final Logger log = 
    Logger.getLogger(VacuumTask.class.getName());

  private DataSource _dataSource;

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

  public void init()
    throws Exception
  {
    if (_dataSource == null)
      throw new Exception("'data-source' is required.");
  }

  protected void performTask()
    throws Exception
  {
    Connection conn = null;
    try {
      conn = _dataSource.getConnection();

      Statement stmt = conn.createStatement();
      stmt.executeUpdate("VACUUM FULL ANALYZE;");
      stmt.close();
    } finally {
      try {
        if (conn != null)
          conn.close();
      } catch (SQLException ex) {
        log.warning(ex.toString());
      }
    }
  }
}

The VacuumTask is configured to run automatically every night at midnight. Since the database is integral to the application, the PeriodicTaskFilter is used to redirect users to an "unavailable" page while the task active. The PeriodicTaskServlet is used to provide an administration interface to the task at the url /admin/example/vacuum.

A <a config-tag="security-constraint"/> is used to limit access to the /admin/ portion of the website. An <a config-tag="authenticator"/> is used to specify the user names and passwords.


WEB-INF/web.xml

<web-app xmlns="http://caucho.com/ns/resin">
  <bean class="example.VacuumTask">
    <init>
      <estimated-average-time>30</estimated-average-time>
    </init>
  </bean>

  <servlet-mapping url-pattern='/admin/example/vacuum'>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${vacuumTask}</periodic-task>
    </init>
  </servlet>

  <bean class="com.caucho.resources.CronResource">
    <init>
      <!-- run every day at 0215 local time -->
      <cron>15 2 *</cron>
      <work>${vacuumTask}</work>
    </init>
  </bean>

  <filter url-regexp="^(?!/admin)+">
    <filter-class>example.PeriodicTaskFilter</filter-class>
    <init>
      <periodic-task>${VacuumTask}</periodic-task>
      <url>/unavailable.jsp</url>
    </init>
  </filter>

  <!-- require 'admin' role -->
  <security-constraint>
    <web-resource-collection>
      <web-resource-name>Admin</web-resource-name>
      <url-pattern>/admin/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>admin</role-name>
    </auth-constraint>
  </security-constraint>

 <authenticator uri="xml:">
    <init>
      <!-- user 'admin' with password 'excellent' is in admin role -->
      <user>admin:FKT/gZPYJ5TIA5uA434mgA==:admin</user>
    </init>
  </authenticator>
</web-app>

Jmx: a management interface for the resource

[doc|jmx.xtp Jmx] provides a mechanism for management of objects on servers. The PeriodicTask implements the PeriodicTaskMBean interface, the PeriodicTaskMBean interface is the Jmx agent's view of the resource.

Jmx uses a naming scheme to store objects for later retrieval. The Jmx name to store the object under is specified with the <a config-tag="mbean-name"/> child of <a config-tag="bean"/>.

Example: WEB-INF/resin-web.xml" language="java

<web-app xmlns="http://caucho.com/ns/resin">

  <bean class="example.PeriodicTask" name="PeriodicTask"
            mbean-interface="example.PeriodicTaskMBean"
            <b>mbean-name="type=PeriodicTask,name=PeriodicTask"></b>
    <init>
      <estimated-average-time>5</estimated-average-time>
    </init>
  </bean>

</web-app>

A simple Jmx lookup of all type=PeriodicTask objects is done in admin/mbean.jmx:

Example: admin/mbean.jsp

  ObjectName query = new ObjectName("resin:type=PeriodicTask,*");
  pageContext.setAttribute("mbeans", Jmx.query(query));

  ...

<c:forEach var="mbean" items="${mbeans}">

  estimatedAverageTime ${mbean.estimatedAverageTime}
  ...


CronResource: timed execution of the PeriodicTask

Depending on the nature of the PeriodicTask, it may be appropriate to configure the task to automatically run at a specified time, or at a specified interval.

The [doc|resources.xtp CronResource] is used to configure the timed execution of the PeriodicTask.

WEB-INF/web.xml" language="java

  <bean class="com.caucho.resources.CronResource">
    <init>
      <cron>*</cron>
      <work>${PeriodicTask}</work>
    </init>
  </bean>


Filter: redirecting users when the task is running

Again depending on the nature of the PeriodicTask, it may be appropriate for access to the web application to be limited while the task is performed. A filter is used to provide this functionality, the filter intercepts requests and if the task is active, redirects to a page giving a "temporarily unavailable" message.

WEB-INF/web.xml" language="java

  <filter>
    <filter-name>PeriodicTaskFilter</filter-name>
    <filter-class>example.PeriodicTaskFilter</filter-class>
    <init>
      <periodic-task>${PeriodicTask}</periodic-task>
      <!-- optional url, if not specified a 503 response is sent. -->
      <url>/unavailable.jsp</url>
    </init>
  </filter>

  <filter-mapping>
    <!-- regexp to match all urls except /admin and /index.xtp-->
    <url-regexp>^(?!/admin|/index.xtp)+</url-regexp>
    <filter-name>PeriodicTaskFilter</filter-name>
  </filter-mapping>

WEB-INF/classes/example/PeriodicTaskFilter.java" language="java

  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

WEB-INF/classes/example/PeriodicTaskFilter.java" language="java

  public void doFilter(ServletRequest request,
      ServletResponse response,
      FilterChain chain)
    throws ServletException, IOException
  {
    if (_periodicTask.isActive()) {
      dispatch( (HttpServletRequest) request, (HttpServletResponse) response);
    }
    else {
      chain.doFilter(request,response);
    }
  }

PeriodicTaskServlet: an administration interface

The PeriodicTaskServlet provides an html interface to the PeriodicTask. It shows the current status of the task, and provides a button to "Run" the task.

The PeriodicTaskServlet needs an instance of PeriodicTask to operate on. The Servlet provides a setter:

WEB-INF/classes/example/PeriodicTaskServlet.java

         language="java">
  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

The configuration of the servlet in web.xml uses the ${...} function to get a reference to the PeriodicTask resource previously stored in with the <a config-tag="bean"/> configuration.

WEB-INF/web.xml" language="java

  <servlet>
    <servlet-name>PeriodicTaskServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${PeriodicTask}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/periodictask</url-pattern>
    <servlet-name>PeriodicTaskServlet</servlet-name>
  </servlet-mapping>


Dependency Injection/Inversion of Control

Dependency injection is a term used to describe a separation between the implementation of an object and the construction of an object it depends on, and the ability for a container (like Resin) to resolve the dependency.

In this tutorial, many components including the administration servlet, the filter, and the CronResource, depend upon a PeriodicTask. Each of these components that depend upon the PeriodidicTask provide a setter:

setter

  PeriodicTask _periodTask;

  public void setPeriodicTask(PeriodicTask periodicTask)
  {
    _periodicTask = periodicTask;
  }

The container (Resin), injects the object.

container injection

  <init>
    <periodic-task>${PeriodicTask}</periodic-task>
  </init>

The simplicity of the code shows immediate benefits. There is no dependency on the environment (needing an application object for example), and no need for cumbersome or error prone code in each component.

There are other benefits as well. Since the container instantiates and sets the object, there is more flexibility in the configuration. The following example shows the use of two distinct periodic tasks.

An example illustrates some of the flexibility of dependency injection.

The first task (Foo) is only run manually, it is not run at a timed interval so the CronResource is not used for it. Neither task causes the application to become unavailable, so the PeriodicTaskFilter is not used.

two distinct periodic tasks

<b>WEB-INF/classes/example/PeriodicTaskFoo.java</b>

public class PeriodicTaskFoo extends PeriodicTask {
  protected void performTask()
    throws Exception
  {
   ...
  }

}

<b>WEB-INF/classes/example/PeriodicTaskBar.java</b>

public class PeriodicTaskBar extends PeriodicTask {
  protected void performTask()
    throws Exception
  {
   ...
  }

}

<b>WEB-INF/web.xml</b>

  <!-- TASK FOO -->

  <bean class="example.PeriodicTaskFoo" name="PeriodicTaskFoo">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </bean>

  <servlet>
    <servlet-name>PeriodicTaskFooServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${PeriodicTaskFoo}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/example/foo</url-pattern>
    <servlet-name>PeriodicTaskFooServlet</servlet-name>
  </servlet-mapping>

  <!-- TASK BAR -->

  <bean class="example.PeriodicTaskBar" name="PeriodicTaskBar">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </bean>

  <bean class="example.PeriodicTaskBar" name="PeriodicTaskBar">
    <init>
      <estimated-average-time>15</estimated-average-time>
    </init>
  </bean>

  <servlet>
    <servlet-name>PeriodicTaskBarServlet</servlet-name>
    <servlet-class>example.PeriodicTaskServlet</servlet-class>
    <init>
      <periodic-task>${PeriodicTaskBar}</periodic-task>
    </init>
  </servlet>

  <servlet-mapping>
    <url-pattern>/admin/example/bar</url-pattern>
    <servlet-name>PeriodicTaskBarServlet</servlet-name>
  </servlet-mapping>

  <!-- bar runs every minute -->
  <bean class="com.caucho.resources.CronResource">
    <init>
      <cron>*</cron>
      <work>${PeriodicTaskBar}</work>
    </init>
  </bean>


See Also

[doc|resources.xtp CronResource]</dt>
Documentation for the usage of CronResource </dd>

Personal tools
TOOLBOX
LANGUAGES