grouper-dev - Generic tile controller
Subject: Grouper Developers Forum
List archive
- From:
- To:
- Subject: Generic tile controller
- Date: Tue, 8 Feb 2005 11:07:06 -0500 (EST)
Apologies for cross posting. The message below was posted to the new
mailing list. If you have any comments please make them to that list.
At the recent Conference call discussing UI methodology I took on an action
item to 'circulate a description of a proposed generic tile controller'. The
first part of this posting is a discussion of what a controller might do. The
second part is a code listing (with comments).
Some further thoughts on the use of Tiles:
Grouper and Signet will have a finite number of entities e.g. for Grouper
group,stem,subject,privilege (group,stem and subject may have fields which
may be considered entities in this context). Often in a UI we will want to
display the same entity in the same way in multiple locations. On the other
hand there may be good reasons why, in a specific context, a different view
of an entity may make sense. The intention for the Grouper UI is to define
a set of views corresponding to context, but to have a default view that is
used if a specific view is not configured. In this way institutions have a
fine degree of control over how entities are displayed.
In the JSP this would look like:
<tiles:insert definition="dynamicTileDef">
<tiles:put name="viewObject" value="subject"/>
<tiles:put name="view" value="memberLink"/>
</tiles:insert>
where 'viewObject' refers to the name of an object in the request or
session, and 'view' corresponds to the context.
The 'dynamicTileDef' definition specifies a 'controller' which resolves the
viewObject and view to a JSP file which renders the object e.g.
memberLinkView.jsp which might look like:
<html:link page="/populateGroupMember.do" name="groupMembership">
<tiles:insert definition="dynamicTileDef" flush="false">
<tiles:put name="viewObject" value="subject"/>
<tiles:put name="view" value="groupMember"/>
</tiles:insert>
</html:link>
Note that a view may include another view. If there is no 'groupMember'
view specified a default view e.g. subjectView.jsp is used and this is a
simple JSP:
<c:out value="${viewObject.desc}" />
The 'dynamicTileDef' controller will use naming conventions within a
properties file to determine which JSP to use, however, an institution
could choose to write their own controller.
A first cut at a controller is shown below:
---------------------------------------------
package edu.internet2.middleware.grouper.ui.actions;
import edu.internet2.middleware.grouper.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import java.util.*;
/**
* Determines correct JSP template based on current tiles attributes
* which specify a 'view' of an 'object' to render.
*
* Institutions could extend / replace this controller to use a different
* algorithm to determine a JSP file name, or to actually generate HTML code
* which would be added to the page output
*
* The algorithm used here is based on a pre-defined set of key lookups
* which try to match potential site specific configuration keys, or failing
that, the
* application default.
*
* The approach actually coded here is a first attempt and would benefit from
refactoring,
* particularly with a view to sharing a controller with Signet e.g.
extending GrouperCapableAction
* is not very generic!
*
* Suggestions on actual keys chosen welcome.
*/
public class GetDynamicTileAction extends GrouperCapableAction {
//------------------------------------------------------------ Action
Methods
public ActionForward grouperExecute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response,
HttpSession session,GrouperSession grouperSession)
throws Exception {
//Get tiles attributes set using 'put' tags
Map tilesAttributes = getTilesAttributes(request); //from
GrouperCapableAction
//Get the ResourceBundle which contains key / values
//we will check in our template finding algorithm
ResourceBundle mediaResources = getMediaResources(request);
//from GrouperCapableAction
//Get the name of th eview and then the actual object we
//are showing a view of
String view = (String)tilesAttributes.get("view");
String viewObject = (String)tilesAttributes.get("viewObject");
Map object = (Map)findAttribute(viewObject,request); //from
GrouperCapableAction
String templateName = null;
//This is quick and dirty based on the fact I am using Maps
//rather than actual objects. A better method might be to
//lookup the class name of the object in a properties file to
//obtain the class name of a TemplateResolver? implementation.
//This approach could work with Maps but I'd need to have Map
//implementations such as SubjectTypeMap, GrouperGroupMap etc
//This would allow sites to add completely new object types
//but leverage the 'view' mechanism
if(object.containsKey("subjectTypeAdapter")) {
templateName =
getSubjectTemplateName(object,view,mediaResources,request);
}else if(Boolean.TRUE.equals(object.get("isGroup"))) {
templateName =
getGroupTemplateName(object,view,mediaResources,request);
}else if(object.containsKey("groupField")) {
templateName =
getGroupFieldTemplateName(object,view,mediaResources,request);
}else {
}
//This is not ideal. Nested tiles are writing to a global
//request / session space.
request.setAttribute("dynamicTemplate",templateName);
request.setAttribute("viewObject",object);
return null;
}
//Here so we don't catch MissingRrsource exceptions in code and can be sure
of null or a value
protected String getResource(ResourceBundle bundle,String key) {
String val = null;
try {
val = bundle.getString(key);
if("".equals(val)) val=null;
}catch(Exception e) {
}
return val;
}
/*
* Depending on the Group type may want to have different template.
* Look for more specific keys first:
* groupType.<type>.view.<view>
* groupType.<type>.view.default
* groupType.view.<view>
* groupType.view.default - Grouper may only set this!
*
*/
protected String getGroupTemplateName(Map group,String view, ResourceBundle
mediaResources,HttpServletRequest request){
String tName = null;
String groupType = (String) group.get("type");
if(groupType==null || "".equals(groupType)) {
groupType=Grouper.DEF_GROUP_TYPE;
}
tName= getResource(mediaResources,"groupType." + groupType + ".view."
+ view);
if(tName==null) {
tName=getResource(mediaResources,"groupType." + groupType +
".view.default");
}
if(tName==null) {
tName= getResource(mediaResources,"groupType.view." + view);
}
if(tName==null) {
tName=getResource(mediaResources,"groupType.view.default");
}
return tName;
}
/*
* Group fields may be displayed differently depending on group type.
* Group field values may be edited - so different defaults applicable
* hence 'prefix' which is determined as view or edit
* Look for more specific keys first:
* groupField.<field>.groupType.<type>.<prefix>.<view>
* groupField.<field>.groupType.<type>.<prefix>.default
* groupField.<field>.<prefix>.<view>
* groupField.<field>.<prefix>.default
* groupField.<prefix>.default - Grouper may only set this
*
*/
protected String getGroupFieldTemplateName(Map groupField,String view,
ResourceBundle mediaResources,HttpServletRequest
request){
String tName = null;
String groupType = (String) groupField.get("type");
if(groupType==null || "".equals(groupType)) {
groupType="base";
}
String prefix = ".view.";
if(view.startsWith("edit.")) prefix = ".";
String field = (String)groupField.get("groupField");
tName=getResource(mediaResources,"groupField." + field +
".groupType." + groupType + prefix + view);
if(tName==null) {
tName=getResource(mediaResources,"groupField." + field +
".groupType." + groupType + prefix + "default");
}
if(tName==null) {
tName=getResource(mediaResources,"groupField." + field +
prefix + view);
}
if(tName==null) {
tName=getResource(mediaResources,"groupField." + field +
prefix + "default");
}
if(tName==null) {
tName=getResource(mediaResources,"groupField" + prefix +
"default");
}
return tName;
}
/*
* Depending on the subject type may want to have a different template. The
* same subject type may be retrieved by different SubjectTypeAdapters, and
* may have different attributes available.
*
* Look for more specific keys first:
* <subjectTypeAdapter>.subjectType.<type>.view.<view>
* <subjectTypeAdapter>.subjectType.<type>.view.default
* <subjectTypeAdapter>.view.<view>
* <subjectTypeAdapter>.view.default
* subjectType.<type>.view.<view>
* subjectType.<type>.view.default - Grouper may only set this
*
*/
protected String getSubjectTemplateName(Map subject,String view,
ResourceBundle mediaResources,HttpServletRequest request){
String tName = null;
String adapterName = (String)subject.get("subjectTypeAdapter");
String subjectType = (String)subject.get("subjectType");
tName=getResource(mediaResources,adapterName + ".subjectType." +
subjectType + ".view." + view);
if(tName==null) {
tName=getResource(mediaResources,adapterName +
".subjectType." + subjectType + ".view.default");
}
if(tName==null) {
tName=getResource(mediaResources,adapterName + ".view." +
view);
}
if(tName==null) {
tName=getResource(mediaResources,adapterName +
".view.default");
}
if(tName==null) {
tName=getResource(mediaResources,"subjectType." + subjectType
+ ".view." + view);
}
if(tName==null) {
tName=getResource(mediaResources,"subjectType." + subjectType
+ ".view.default");
}
return tName;
}
}
---------------------------------------------------------------------------------------------------------------------
- Generic tile controller, gary . brown, 02/08/2005
Archive powered by MHonArc 2.6.16.