Using Views in Induction
This tutorial discusses the use of views in Induction. A view is an abstraction that simplifies handling responses that require non-trivial content generation at runtime. This tutorial assumes familiarity with the Getting Started Tuturial.
Following are some features of views in Induction:
- A view may be activated as follows:
- Directly: in response to an HTTP request (the view resolver maps HTTP requests to view) (NEW! since v1.2.0b)
- Indirectly: in response to a value returned by a controller
- A view is a class that implements one of the Induction view interfaces (we will discuss the specific view interfaces shortly).
- An instance of a view class is returned by a controller. Induction processes the controller's return value based on the type information of the value. Since the view is returned no explicit calls into the Induction framework are needed in the controller class.
- The view class serves to encapsulate the data used by the view. This encapsulation is what enables the analysis of the data dependency of a template (via the view) using Java dependency analysis tools in an IDE.
- The view interface specifies the type of view processor (the view interfaces corresponding to each template type are: Template, Text, Image, ImageStream) that will be used to process the view, not the specific implementation of the processor. For example a view class that implements the com.acciente.view.Template interface only specifies that this view should be processed by a template engine, it does not specify the actual templating engine that should be used (the latter is determined by the configuration of the Induction instance the application is run on).
Writing our first view - HelloWorld
Let's use a simple example to illustrate some of the above features. We will write a simple HelloWorld application that uses an Induction view to display a string to the browser. We will write two different versions of our HelloWorld application to illustrate two different view types.
The first version will use the Text view interface. The Text view interface is designed to be used to send a string to the browser. The view class is shown below:
package demoapp.helloworld2_app;
import com.acciente.induction.view.Text;
public class HelloWorld2View implements Text
{
public String getText()
{
return "Hello World, using a Text view";
}
public String getMimeType()
{
return "text/plain";
}
}
If you deployed this example similar to the example in the Getting Started Tuturial then pointing your browser at the URL http://localhost:8080/induction-demo/helloworld2 should print Hello World, using a Text view to the browser.
Our HelloWorld2View class above implements the com.acciente.view.Text interface. When Induction encounters an implementation of this interface it calls the getText() method of the interface to retrieve the string that should be returned to the browser, and the getMimeType() method to determine the mime type that should be returned for the text content. If getMimeType() return null then text/plain is assumed.
Next let's look at how a controller can use our HelloWorld2View class:
package demoapp.helloworld2_app;
import com.acciente.induction.controller.Controller;
/**
* A simple controller that uses a Text view to display hello world
*/
public class HelloWorld2Controller implements Controller
{
public Class handler()
{
return HelloWorld2View.class;
}
}
If you deployed this controller then pointing your browser at the URL:
http://localhost:8080/induction-demo/helloworld2.action, should print the string Hello World, using a Text view to your browser.
Next let's write a HelloWorld application that uses the Freemarker templating engine to display our "Hello World" string. We'll again start with the view class:
package demoapp.helloworld3_app;
import com.acciente.induction.view.Template;
/**
* A HelloWorld view using a freemarker tenplate
*/
public class HelloWorld3View implements Template
{
public String getTemplateName()
{
return "HelloWorld3.ftl";
}
public String getMimeType()
{
return "text/plain";
}
}
In the HelloWorld3View class above the getTemplateName() method is expected to return the name of a template file. Induction attempts to find a template with the returned by getTemplateName() in the template path configured. If a template is found Induction process the template using the configured template engine (in our example we use the Freemarker templating engine).
Induction treats the view class as a Java bean and make all the views bean properties available in the template. For example, if our HelloWorld3View class had a getUserName() method, then it would be valid to reference ${userName} in our Freemarker template.
Shown below is the simple HelloWorld3.ftl Freemarker template referenced by the HelloWorld3View view class:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<HTML>
<HEAD>
</HEAD>
<BODY>
Hello World, using a Freemarker template
</BODY>
</HTML>
You should put the HelloWorld3.ftl in a folder in your file system and ensure that the Induction configuration XML points to the location of your templates. For example if your HelloWorld3.ftl is in the folder
c:/project/demoapp/helloworld3_app/templates, then the template path section of Induction XML would be as shown below:
<templating>
<template-path>
<directory>c:/project/demoapp/helloworld3_app/templates</directory>
</template-path>
</templating>
If you choose to put the HelloWorld3.ftl template in inside your .war file, in say /WEB-INF/templates, then the Induction XML would be as shown below:
<templating>
<template-path>
<web-app-path>/WEB-INF/templates</web-app-path>
</template-path>
</templating>
It is recommended that you keep the templates on the file system during development. Placing the templates inside the .war file is not recommended during development, since this would require a rejar/redeploy every time the template changes.
Again after you deploy this example, pointing your browser at the URL:
http://localhost:8080/induction-demo/helloworld3, should print the string Hello World, using a Freemarker template to your browser.
The types of views supported
The following table shows the types of views currently supported in Induction:
Inducton view type | Purpose of the view type |
---|---|
com.acciente.view.Template | Used to create a view that returns text generated by a templating engine |
com.acciente.view.Image | Used to create a view that returns image data. The Image data is returned to Induction as a byte array |
com.acciente.view.ImageStream | Used to create a view that returns image data. The Image data is returned to Induction using an input stream |
com.acciente.view.Text | Used to create a view that returns text data. The text data is returned to Induction as a string |
Notes on Best Practices
It is best that a view class expose (via its public accessors) the minimum amount of data needed by the view's associated template. However from a controller point of view it may be convenient to pass, to the view constructor, more data than the view needs to expose to the template. For example a view may only need a few attributes from a model, but it may be convenient to pass the entire model object to the view constructor.
In such cases, the view class may internally store (in instance variables) more data than is required by the template but expose only the minimum required set of data via its accessor methods. In this case the view class serves as data filter reducing the coupling of the template to models and other data in an application.
Conclusion
This concludes our tutorial about using views in Induction. Models are introduced in the Models Tutorial.