Dashboard > uPortal Channels > Home > JSP Model II Channel Type
uPortal Channels Log In   View a printable version of the current page.
JSP Model II Channel Type

Added by Mark R. Boyd , last edited by Andrew Petro on Jun 18, 2007  (view change)
Labels: 
(None)

The JSP Model II channel type is new in uPortal 2.6. This channel type is designed for using Java Server Pages in a Model II manner meaning that a controller class handles business object interaction and then delegates to JSPs to render the appropriate view. Any dynamic information to be embedded within a JSP is expected to be acquired from business objects passed from the controller. Such objects should be plain old java objects, POJOs, to conform to traditional view rendering standards. Of course there is no way to enforce this approach so such objects could be designed to go all of the way to the database to accomplish their work. Nevertheless, the model II approach is encouraged by a required declaration of a controller class as part of publishing the channel. Lets take a look at publishing an example channel and then dive into the details of building a controller and JSPs to be used in this channel type.

When publishing a channel of this type the workflow screens appear as follows. A user with channel publishing permission logs in and selects the Channel Admin link followed by Publish New Channel. The JSP channel type is then visible in the list of channel types. (Click the image for the larger view.)

The user selects the JSP Model II channel type and presses the next button. The view is then replaced allowing them to enter the general channel parameters: Name, Title, Functional Name, Timeout, and Secure. Upon pressing the next button they are then taken to a JSP specific workflow step allowing them to enter the name of the controller class for the JSP channel. As noted in the image the controller class must implement the org.jasig.portal.channels.jsp.IController interface which will be discussed below. (To publish a sample JSP channel included in the portal specify a controller of org.jasig.portal.channels.jspSample.Controller and indicate that it supports the Editable, Has Help, and Has About channel controls.)

Following the controller step the user is taken to the Controller Parameters step. Controllers can customize their behavior for a specific publication by watching for and acting upon parameters that can be added in ad-hoc fashion when publishing a JSP channel. Note that the set of optional parameters supported for a given controller must be obtained from documentation for that controller.

Any parameters added in this step are available to the controller via its instance of ChannelStaticData passed to it via the setStaticData() method. Parameters are available from the ChannelStaticData's getParameter() method via passing it the name of the parameter prefixed with "JSP.". For example, if a controller parameter with name, refreshRate, and value, 60, was added, then the channel would obtain a String containing the characters, "60", via calling:

channelStaticData.getParameter("JSP.refreshRate");

The remaining workflow steps are as expected. The user can indicate if this channel supports help, about, and edit, a category for the channel can be selected, and the groups that can use the channel can be indicated. Upon subscribing to the channel they see a typical channel with content as shown below for the sample JSP channel provided with the portal. However, the key difference is that this content is being generated by a JSP accessing business objects passed to it by the controller. The controller for this channel handles the help, about, and edit events by adding an additional object to a list and then passing the list to a JSP for rendering. The running channel after pressing these links a number of times can be seen in the attached image.

Architecture

The JSP channel type is implemented as a channel that accepts a plugged-in controller object that must implement the org.jasig.portal.channels.jsp.IController interface. This interface allows the channel to pass common uPortal information objects like ChannelStaticData and ChannelRuntimeData to the controller and provides additional mechanisms for obtaining from the controller the location of a JSP to which to delegate to have the channel's content rendered. Implicit in the design is a mechanism for passing from controller to the JSP, java beans that hold dynamic data and can be used during rendering to embed that data in the UI.

So the architectural separation of the various pieces used for presenting a typical published JSP channel type are shown below. The channel in the org.jasig.portal.channels.jsp package which implements the JSP channel type is already provided by the portal. Only the controller, related class and property files, and JSP files need to be provided prior to publishing. Here the sample channel provided with the portal are used as an example plugged-in implementation.

IController Interface

The IController interface extends the ICacheable interface so that the controller can tell the infrastructure when re-rendering of content is needed. The channel also implements the ICacheable interface but delegates to the controller all calls made to these methods. (See the section on the ICacheable interface below.) The IController methods are as follows:

public void setStaticData(ChannelStaticData csd, HttpSession s);
    public void receiveEvent(PortalEvent ev);
    public Map processRuntimeData(ChannelRuntimeData drd);
    public String getJspToRender();    
    public Map getJspMap();

The setStaticData() method is identical to the method of the same name in the IChannel interface. It is only called when the controller is instantiated and passes to the controller static information like the person running the channel.

The receiveEvent() method is called by the channel's receiveEvent() method allowing the controller to handle channel events.

The processRuntimeData() method allows the controller to receive the ChannelRuntimeData object to handle information posted back to the channel. It also provides access to the HttpSession object which can be used to pass information between the controller and the JSPs or even between other JSPs that are not part of this channel or can even pass information to other servlets. The returned Map object can be null or contain mappings to java beans objects that should be made accessible to the JSPs. Any objects passed back via this map are placed in the HttpServletRequest object that gets passed to the JSPs. Two keys are reserved for use in this map. The keys, baseActionUrl and baseMediaUrl, will be discared along with their value objects if included in the Map. These keys are used by the channel itself to pass URLs to the JSPs for use in forms and images.

The getJspToRender() method is called immediately after processRuntimeData() returns and lets the controller indicate to which JSP the channel should delegate to have content rendered and handed back. The actual value passed back is not a path to the JSP but rather is a string value that is the key to acquire the path to the specific JSP. The mappings of keys to paths are otained via the getJspMap() method.

The getJspMap() is called only once in the lifetime of the controller and immediately after setStaticData() returns. It returns a java.util.Map implementation containing mappings of keys to JSP file paths. The values in this map are then used to resolve the keys returned from getJspToRender() in order for the channel to delegate to a JSP to render the content.

JSP Paths and File Locations

The paths handed back in the Map returned by getJspMap() may differ depending on if the channel is deployed in CAR format or in non-CAR traditional format by pushing all resources including JSPs into specific web server directories. The processing is as follows:

1st

If the path does not start with a '/' character then the path is assumed to be relative to the package of the controller and that package path is appropriately prepended to the JSP path. For example, the jsp sample channel creates its map of JSPs as follows:

public Map getJspMap()
    {
        Map jsps = new HashMap();
        jsps.put(JSP, "events.jsp");
        return jsps;
    }

The events.jsp is located in the same directory as the Controller source and class files. Since the path is not prefixed with the '/' character this will be converted into the new path org/jasig/portal/channels/jspSample/events.jsp and used for the remaining steps.

2nd

If the path is realtive to the IController implementation as in the previous step or the channel was deployed in CAR format then a configurable prefix location is prepended to the path. That prefix is defined by the org.jasig.portal.channels.jsp.Deployer.context.relative.jspPath property in portal.properties if found and defaults to a value of /WEB-INF/classes which is also the value specified in portal.properties by default in the uPortal codebase. This then produces a fully qualified path relative to the uPortal web application's servlet context.

In the 2nd step above, the reason that such a path is used in the case of CAR deployment is that JSPs located in CARs are inaccessible to the web server for compiling and are extracted automatically by the portal and placed beneath the location specified with the above portal.properties property and relative to thier location within the CAR. Additionally, to make class and property file resources available to such JSPs such files included in the CAR are extracted to locations indicative of their path within the CAR relative to the property indicated in the 2nd step. To be clear, currently any files ending with ".jsp", ".jsf", ".jspf", ".class", or ".properties" are extracted in this manner. For example, suppose that the jsp sample channel were installed as a CAR containing its resources:

org/jasig/uportal/channels/jspSample/Controller.class
org/jasig/uportal/channels/jspSample/events.jsp

After publishing a JSP Channel Type referencing the Controller class, when the first instance of that JSP Channel Type were instantiated in a layout these resources would be extracted to the following locations assuming the values identified in the 2nd step above and made accessible to the web server and and web application classloader.

<container>/webapps/luminis/WEB-INF/classes/org/jasig/uportal/channels/jspSample/Controller.class
<container>/webapps/luminis/WEB-INF/uPortal/org/jasig/uportal/channels/jspSample/events.jsp

Since the JSP and the controller are located in the same package path, the controller can specify the location of the JSP in relative format in the Map object returned from the getJspMap() method as noted above. It could also have been specified with the following code:

public Map getJspMap()
    {
        Map jsps = new HashMap();
        jsps.put(JSP, "/org/jasig/uportal/channels/jspSample/events.jsp");
        return jsps;
    }

Once deployed, the files will not be deployed again unless that CAR from which they were extracted is modified or the files in the directory locations are removed. Information on when deployment took place, what items were deployed, and the CAR from which they were extracted is written in a file named jspCars.deployed located <container>/webapps/uPortal/WEB-INF. This file can be read for reference but should not be changed. Note that the path specified above that includes the prefixed '/' character would cause the server to fail to find the JSP if the channel were deployed in traditional manner. Such channels are allowed more flexibility concerning the location of JSPs which leads us to step 3.

3rd

If a channel is not deployed as a CAR and it is not relative to its controller meaning that its path begins with a '/' character, then that path is accepted as-is and is looked for relative to the uPortal web application's servlet context.

ICacheable Interface

The ICacheable interface is an optional interface that channels can implement to convey to the portal that the channel's generated content can be cached and reused if there is no change to be viewed in that content if rendered again. If a channel indicates that previous content is still valid, then the portal embeds the cached version and does not call the channel's renderXML or renderCharacters methods as shown in the diagram below. The passage of time is indicated as you read from the top of the diagram to the bottom. The various objects generated along the way and the methods called on those objects relative to each other in time is indicated. For example, the generateKey() method falls lower in the diagram than the setRuntimeData() method and hence is called some time after setRuntimeData().

The ChannelCacheKey class is provided in the org.jasig.portal package. It provides three pieces of information:

setKey(String), getKey() provide a String key to be used in the portal's internal cache tables. Through the use of multiple different values a channel can have different views cached at the same time and those cached versions used until the content in those views becomes stale.
setKeyValidity(Object), getKeyValidity() provides an Oject referred to as the validity object that will be handed back to the channel's isCacheValid() method to assist the channel in determining the freshness of the content represented by this cache key object.
setKeyScope(int), getKeyScope() provide an integer value which should be either SYSTEM_KEY_SCOPE or INSTANCE_KEY_SCOPE both of which are public constants declared on the ChannelCacheKey class. System scope is rarely used. If specified then the String key value passed to setKey() must be unique system wide. For instance scope the key must only be unique within a single user's session. But even here, care must be taken so that content from two instances of the same channel but displaying different content don't impact each other. Typically such a key would incorporate the channel's subscribe ID which is unique within the user's layout.

The following object instance diagram should help clarify why uniqueness for keys is important. There is one of these models for system scope and one of these models per user for instance scope. For those familiar with the internal workings of uPortal, both the system model and the instance model are stored in the ChannelManager class. The system scope Hashtable is in a static variable. The instance scope Hashtable is in an instance variable and there is one instance of ChannelManager instantiated per user session.

Restrictions on JSP Functionality

The JSP channel type does place the following restrictions on JSP functionality.

1) Since content is being generated that is embedded into a larger HTML document, that content should not have the HTML, HEAD, or BODY wrapping elements.
2) In the case of CAR deployment only the files indicated in the 3rd step above are extracted. All other resources are embedded within the CAR. This means that image references embedded within the HTML generated by the JSPs must use the appropriate BaseMediaUrl prefixed to a relative image location. This is the same requirement as is used in channels today. The only difference is in how that base media URL is passed into the rendering technology. For channels the value of both the base media and base action URLs are typically passed in as stylesheet parameters. For JSPs they are placed on the HttpServletRequest object passed to the JSPs and are accessed using getAttribute() with values of "baseActionUrl" and "baseMediaUrl". Therefore they are accessible from within a JSP via the implicit "requestScope" variable as "requestScope.baseMediaUrl" and "requestScope.baseActionUrl" using expression language.
3) Related to item 2 is the use of other elements that cause the browser to call back to the server to obtain additional content to be embed into the HTML generated by the JSPs. Examples are javascript files. These too would have to prefix the base media URL to provide access to the browser to properly pull those pieces from the web server.
4) Finally, since the items in 3 are pulled using a special URL that contains a query parameter, relative URLs within any included javascript file may not function properly. This is a known issue in the JA-SIG community concerning including javascript files within a CAR and should be avoided for the time being.

(mrb 2007.03.14)

Powered by a free Atlassian Confluence Open Source Project License granted to Java Architectures Special Interest Group. Evaluate Confluence today.
Powered by Atlassian Confluence 2.7.3, the Enterprise Wiki. Bug/feature request - Atlassian news - Contact administrators