blob: ae2a3a18885ca4b176734b0d9cfbed12273c6185 [file] [log] [blame]
<?xml version="1.0"?>
<!--
/*
* Copyright 2001-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<document>
<properties>
<title>Turbine Services - RunData Service</title>
</properties>
<body>
<section name="RunData Service">
<p>
RunData is an interface that is passed around within Turbine. RunData
provides the threading mechanism, as there is one RunData object per
HTTP request. The RunData service manages the isues surrounding multiple
requests being accepted. TurbineRunData is the interface that is
specific to the Turbine RunData service, and via the recyclable
interface can be sent back to the Factory for recycling.
</p>
<p>
RunData objects should never be held on to across requests. They are
considered one time only objects.
</p>
<p>
All this higher level processing by the service means that for each HTTP
request there is an interface that is castable to, or available, that
can be used to access all information to do with that request. As an
example, information such as the content type of the request and the
response can be queried or sent, as well as other information
surrounding servlet HTTP management, such as Sessions, PrintWriters as
well as Turbine specific information such as Users, AccessControlLists,
Templating, Error Handling and Contexts.
</p>
</section>
<section name="Configuration">
<p>
In the TurbineResources.properties the service needs to be defined for
Turbine to initialize with.
</p>
<source><![CDATA[
# -------------------------------------------------------------------
#
# S E R V I C E S
#
# -------------------------------------------------------------------
# Classes for Turbine Services should be defined here.
# Format: services.[name].classname=[implementing class]
#
# To specify properties of a service use the following syntax:
# service.[name].[property]=[value]
services.TurbineRunDataService.classname=org.apache.turbine.services.rundata.TurbineRunDataService
.
.
.
# -------------------------------------------------------------------
#
# R U N D A T A S E R V I C E
#
# -------------------------------------------------------------------
# Default implementations of base interfaces for request processing.
# Additional configurations can be defined by using other keys
# in the place of the <default> key.
# -------------------------------------------------------------------
services.RunDataService.default.run.data=org.apache.turbine.services.rundata.DefaultTurbineRunData
services.RunDataService.default.parameter.parser=org.apache.turbine.util.parser.DefaultParameterParser
services.RunDataService.default.cookie.parser=org.apache.turbine.util.parser.DefaultCookieParser
]]></source>
</section>
<section name="Using RunData">
<p>
As RunData encapsulates all aspects of Turbine's gathering the
HttpRequest and sending the HttpResponse, any status to do with the
Request can be queried and any manipulation of the final response can be
carried out through the RunData Object.
</p>
<p>
Turbine is a servlet and the functionality equated with the
javax.servlet and javax.servlet.http can be manipulated through the
RunData interface. One of the most useful components of the Servlet
libraries was Sessions. These are accessed through RunData; it also
provides direct access to the PrintWriter, Server details, Content
Types, ContextPath, Redirections, Client details, etc. Some of the
functions which equate with the servlet libraries are:
</p>
<source><![CDATA[
getLocale()
setLocale(Locale locale)
getCharSet()
setCharSet(String charset)
getContentType()
setContentType(String mimetype)
getOut() //get PrintWriter Object
getRedirectURI()
getRemoteAddr()
getRemoteHost()
getRequest()
getResponse()
getServletContext()
getSession()
getStatusCode()
]]></source>
<p>
The get/setLocale(), get/setCharSet() and get/setContentType() methods
are used for specifying the locale, character encoding and content type
of the body of the servlet response.
</p>
<p>
The method setLocale() is called to specify explicitly the locale
of the response. If setLocale() is not called, the "locale.default.language"
and "locale.default.country" properties from Turbine Resources are used to
determine the locale. If these properties are not set, the JVM's default
locale determines the locale.
</p>
<p>
If the locale is set to something else than the default locale or Locale.US,
an explicit encoding is not specified with the setCharSet() method or the
"locale.default.charset" property, and the main MIME type of the content is
"text", the getContentType() method adds a locale specific encoding (charset)
to the content type automatically.
</p>
<p>
The locale specific charset is obtained from the MimeTypeService, which
maintains mappings between locales and charsets.
</p>
<p>
As always consult the Javadocs for more detail.
</p>
<p>
To use Turbine to only manipulate the functions that came with the Sun
Servlet libraries is to miss out on Turbine's power. Turbine is a
framework which enables manipulation of the HttpResponse and HttpRequest
above and beyond the simple Servlet libraries. Turbine has services and
layers surrounding those available with the Response and Request that
allow easier creation and management of Websites and Web-enabled
Applications. In fact you wont have to type import javax.servlet.*
again!
</p>
</section>
<section name="Session Management">
<p>
Sessions are managed in Turbine via the User interface. The User
interface allows for a blend of cookie management, memory management and
relational database to be used to manage a user's session. A user of the
site can have their Turbine session set as either temporary storage or
permanent storage. The permanent storage will survive a servlet engine
restart. How all this is managed by Turbine is transparent to the Java
Engineer. As an example assume we want to monitor how often a user
returns to the website we are developing and we want to reward them for
their returning interaction:
</p>
<source><![CDATA[
//in Login Action class
public void doPerform(RunData data, Context context)
throws Exception
{
//get the Parameters, username and password
ParameterParser params = data.getParameters();
String loginname = params.getString("username");
String password = params.getString("password");
try
{
//cast to TurbineUser interface
//and check if user is in system
TurbineUser user = (TurbineUser)
TurbineSecurity
.getAuthenticatedUser(loginname, password);
//put User into Session
data.setUser(user);
//mark the User as logged in
user.setHasLoggedIn(new Boolean(true));
//add to the access counter
user.incrementAccessCounter();
//add to the access counter for the session
user.incrementAccessCounterForSession();
//check to see if user is to have
//their status changed to valued
if(user.getAccessCounter() > 500 )
{
//set into persistant storage
//that our visitor is now a
//valued user
user.setPerm("valued", new Boolean(true));
}
data.save();
}
catch (Exception e)
{
//error handling
}
}
]]></source>
<p>
While skeletal this shows a good example of permanent and temporary
management of User information. The line data.setUser() puts the User
into session, the hasLoggedIn() method updates the User Object to
reflect the fact that the session has passed Authentication; however
until the RunData's save method is called both the User and hasLoggedIn
flag are only existing in Turbine's memory. Neither become a part of
RunData's HttpSession until they are saved into the session through
data.save(). The AccessCounter is persistent storage and is saved into
the database. The AccessCounter for the session counts the number of
pages that are requested throgh Turbine for the user's session. Once
their session logs out or the session times out, that information is
lost. The user.setPerm() method allows for information to be stored
persistently into the database as a HashTable entry. The example above
was intended to show that information can be handled through a
consistent interface allowing for the management at the
request/response, session and persistent levels without any direct
manipulation of the HttpRequest, HttpResponse, HttpSession or Relational
database. As always, refer to the Javadocs for more information on the
RunData, User and TurbineUser interfaces.
</p>
</section>
<section name="Parameter and Cookie Parsing">
<p>
One of the most useful parts of the RunData interface is the easy
retrieval of parameters attached to a request. The ParameterParser and
CookieParser Interfaces are available through the RunData interface and
provide convenience methods for gathering parameters from either the URI
or Session. Turbine handles parameters as name/value pairs through the
URI via the BaseValueParser object, allowing the parameters to be
requested as a Java type rather than a catch-all:
</p>
<source><![CDATA[
/** the doPerform method from Invoice.java Action class */
public void doPerform(RunData data, Context context) throws Exception
{
//get parameters
ParameterParser params = data.getParameters();
/**
* Where "units" is the HTML Input Form name
*/
int units = params.getInt("units");
/**
* Get the description, if there is no entry from the
* HTML input form, set the default as "No Description".
*/
String description = params.getString("description","No Description");
/**
* If there is no total, set the value to 0.
*/
BigDecimal total = params.getBigDecimal("total",new BigDecimal(0));
}
]]></source>
<p>
The above example shows gathering of name/value pairs from HTML Form
Inputs and setting default values for those forms. In the case of
description, if the description is null, then the default value "No
Description" will be substituted. The Javadocs for ParameterParser show
more information on the methods available.
</p>
</section>
<section name="Security Management">
<p>
The RunData interface also exposes security management methods and
information which are encapsulated into a request. The RunData interface
exposes the AccessControlList Object, which encapsulates the Permissions
and Roles for the Groups the User is in. The getACL() method allows for
the permission of the User to be queried against their ACL.
</p>
<source><![CDATA[
/** the doPerform method from DeleteInvoice.java Action class */
public void doPerform(RunData data, Context context) throws Exception
{
//check if the User is authorized before
//deleting the invoice
AccessControlList acl = data.getACL();
if(acl.hasPermission("deleteinvoice"))
{
//delete invoice logic
}
else
{
data.setMessage("You do not have permission to delete an invoice.");
data.setTemplate(data, "UnauthorizedRequest.vm");
}
}
]]></source>
<p>
The above example gets the AccessControlList Object for the User through
the RunData interface. The ACL is used to check against the Permissions
the User has, the PermissionSet, or a list of all permissions the User
has, most likely taken from a database. In this example, the check is
against the string "deleteinvoice". If the User has the permission, they
will be able to delete the invoice, otherwise the User will get an
unauthorized request Velocity screen.
</p>
</section>
<section name="Template Management">
<p>
The RunData also exposes methods to manipulate Screens, Actions, Pages
and Layouts. The templating service assembles the screens, actions and
layouts as well as exposing template methods. The methods for managing
screens and actions includes:
</p>
<source><![CDATA[
getAction()
getLayout()
getLayoutTemplate()
getScreen()
getTemplateInfo() //returns TemplateInfo Object
hasAction()
hasScreen()
setAction()
setLayout()
setLayoutTemplate()
setScreen()
setScreenTemplate()
]]></source>
<p>
For more information on how to use the RunData Interface with Velocity
templates and the Velocity context, view the Velocity Site
documentation.
</p>
</section>
<section name="Messaging">
<p>
One of the other useful wrappers the RunData interface provides access
to is messaging. The Message can be set as a String, an ECS Element or
as a FormMessages object. RunData contains access to other convenience
methods to do with Messaging such as:
</p>
<source><![CDATA[
addMessage(Element msg)
addMessage(String msg)
hasMessage() //if the request has a message
getMessage()
getMessageAsHTML()
getMessages() //returns a FormMessages Object
setMessage(String msg)
setMessage(Element msg)
setMessage(FormMessages msgs)
]]></source>
<p>
An example of using messages with Velocity templates in an action is
below:
</p>
<source><![CDATA[
/** the doPerform method from Invoice.java Action class */
public void doPerform(RunData data, Context context) throws Exception
{
data.setMessage("A message for output.");
data.setTemplate(data, "Test.vm");
}
]]></source>
<p>
This would be accessed in the Velocity template via:
</p>
<source><![CDATA[
#*
Velocity file, Test.vm, showing messaging example.
*#
$data.getMessage()
]]></source>
<p>
And the output would be:
</p>
<source><![CDATA[
A message for output.
]]></source>
<p>
The Javadocs for RunData show all the methods available through the
interface and is definitely the place to start when looking for more
information on what RunData exposes. The RunData interface is one of the
most important areas for a Java Engineer to understand and be familiar
within the Turbine Framework. Understanding RunData is of continual
benefit.
</p>
</section>
</body>
</document>