Acciente Company Logo

Using Models in Induction

  1. Using Models in Induction
    1. Accessing Model Objects
    2. Configuring Models
    3. Instantiating Model Objects
      1. Method 1 - Singleton Public Constructor
      2. Method 2 - Model Factory
    4. Scoping Model Objects
    5. Interaction Between Models (Model-to-Model Injection)
    6. Notes on Best Practices
    7. Notes about the Sample Applications

This tutorial discusses the use of models in Induction. The term model is used in Induction to refer to a class that implements application functionality. A model could be a J2EE session bean, an object that wraps a web service or any other type of Java object.

Accessing Model Objects

A typical place to use a model would be in a controller's handler method. Let's illustrate the use of models in a controller using an example. The example below shows how the controller class BarController accesses the model class BarModel in its handler method:

package demoapp.models_app;

import com.acciente.induction.controller.Controller;
import com.acciente.induction.controller.Response;

import java.io.IOException;

public class BarController implements Controller
{
   public void handler( Response oResponse, BarModel oBarModel ) throws IOException
   {
      oResponse.setContentType( "text/plain" );
      oResponse.out().println( "BarModel : " + oBarModel );
   }
}

Note that our handler method simply declares a formal parameter of the model class type. Binding to a model from your controller is that simple. Induction injects an instance of the BarModel model class into the handler method. Next let's examine how Induction is configured with information about our BarModel class.

Configuring Models

We will discuss model configuration by way of an example. To define our BarModel class as a model in Induction we have the following lines in our Induction XML:

	<model-defs>
		<model-def>
			<class>demoapp.models_app.BarModel</class>
			<scope>session</scope>
			<factory-class>demoapp.models_app.BarModelFactory</factory-class>
		</model-def>
	</model-defs>

Let's take a look at the definitions in the XML above. All model related configuration is defined under the <model-defs> section of the XML configuration. Each model has one <model-def>. Now lets take a look at the definitions for our BarModel model class within the <model-def> section:

Instantiating Model Objects

Induction support two modes of model instantiation, one mode favors simplicity and the other provides complete control. We discuss each of the modes below.

Method 1 - Singleton Public Constructor

The singleton public constructor mode of model instantiation is assumed if no factory class is defined for the model. In this mode Induction creates the model object by calling the singleton public contructor of the model class.

As the name implies, this mode requires that the model class have only public construtor. On invoking the constructor Induction will check the types of the formal parameters of the constructor and inject values for the types supported by Induction. Induction injects values for the following types:

Type Description
javax.servlet.http.HttpServletRequest the servlet request
javax.servlet.ServletConfig the servlet config object
Config.ModelDefs.ModelDef the configuration data specified to setup this model (not typically used)
model_class_name a reference to another model class, the instance of the other model class, say A, is managed to conform scope defined for the model class A. The ability inject one model into another model in Induction is referred to as model-to-model injection

Next we discuss a a method that provides more control over model instantiation.

Method 2 - Model Factory

Specifying a factory class provides the most control over model instantiation. A model factory does not implement any special interface, it simply needs to have a method named createModel. The createModel is called with parameter injection. The types supported for parameter injection into the createModel method is identical to that described for the singleton public constructor above.

The example below illustrates a model factory class:


package demoapp.models_app;

import javax.servlet.ServletConfig;
import javax.servlet.http.HttpServletRequest;

/**
 * This class is an Induction model factory. The only requirement is that this class have single
 * method named createModel().
 */
public class BarModelFactory
{
   private  TarModel    _oTarModel;

   /**
    * Our createModel() is very simple, but you are free make it as fanciful as your
    * model instantiation demands. We declare the HttpServletRequest, ServletConfig
    * and TarModel parameters to demonstrate the injection of these values into the
    * createModel() method. HttpServletRequest, ServletConfig are "built-ins", while
    * TarModel is just another model class
    *
    * @return a BarModel object
    */
   public BarModel createModel( HttpServletRequest oRequest, ServletConfig oConfig, TarModel oTarModel )
   {
      System.out.println( "request=" + oRequest  );
      System.out.println( "config=" + oConfig  );
      System.out.println( "tar=" + oTarModel  );

      _oTarModel = oTarModel;

      return new BarModel( System.currentTimeMillis() );
   }
}

Scoping Model Objects

The options for model scope are application, session and request.

Interaction Between Models (Model-to-Model Injection)

Model-to-model injection comes into play when you need an instance of one model, say A, in another model, say B. Instead of explicitly instantiating an instance of model A in model B and managing its lifecycle, with no added configuration, Induction's parameter injection mechanism can be used to link the model objects. Ofcourse the model objects that are linked could have different scopes. For example, model A may be application scope and model B may be session scope.

Induction injects an instance of one model class, say A, into the constructor of another model class, say B, based on the constructor's parameter list of model class B. Model-to-model injection also works when a factory class is used, in this case the injection is done into the createModel method.

The scope of the instance of model class A is managed exactly as if the model was otherwise accessed (such as in a controller). So for example, if model class A has Session scope then all model objects (and controllers) into which A is injected will refer to the same instance of model class A for a given session.

When performing model-to-model injection, Induction will check for cyclic dependencies and throw an exception if any cycles are detected.

Notes on Best Practices

For more complex applications it is recommended that you use an interface to represent the public methods of a model. This interface should then be specified in the Induction XML as the model class name instead of the actual model implementation class name. This approach requires that model be instantiated via model factory class since the singleton public constructor cannot be used with an interface.

If you want the option to be able to reuse a single factory class to instantiate different model types this is supported by Induction. This means that the same model factory class will be specified in the XML for the respective models that share the model factory class.

Ofcourse then the createModel factory would need to know which model class needs to be instantiated when Induction calls the createModel method. This is achieved by declaring a formal parameter of type Config.ModelDefs.ModelDef in the createModel method. The Config.ModelDefs.ModelDef object injected has the following methods:

Notes about the Sample Applications

The models_app demo illustrates the use of models. The models_app demo also illustrates the concept of model-to-model dependency injection.

The counter_app demo also illustrates a simple model (a counter) that is accessed by three different controllers. The counter_app demo is also home to a controller that just displays the cookie information in a request (this needs to move to its own package).