Return-Path: Delivered-To: apmail-jakarta-jetspeed-dev-archive@apache.org Received: (qmail 31897 invoked from network); 3 May 2002 15:23:44 -0000 Received: from unknown (HELO nagoya.betaversion.org) (192.18.49.131) by daedalus.apache.org with SMTP; 3 May 2002 15:23:44 -0000 Received: (qmail 22921 invoked by uid 97); 3 May 2002 15:23:44 -0000 Delivered-To: qmlist-jakarta-archive-jetspeed-dev@nagoya.betaversion.org Received: (qmail 22778 invoked by alias); 3 May 2002 15:23:43 -0000 Delivered-To: jakarta-archive-jetspeed-dev@jakarta.apache.org Received: (qmail 22770 invoked by uid 97); 3 May 2002 15:23:43 -0000 Mailing-List: contact jetspeed-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Subscribe: List-Help: List-Post: List-Id: "Jetspeed Developers List" Reply-To: "Jetspeed Developers List" Delivered-To: mailing list jetspeed-dev@jakarta.apache.org Received: (qmail 9799 invoked by alias); 3 May 2002 15:07:47 -0000 X-Antivirus: nagoya (v4198 created Apr 24 2002) Date: 3 May 2002 15:07:40 -0000 Message-ID: <20020503150740.18848.qmail@icarus.apache.org> From: ggolden@apache.org To: jakarta-jetspeed-cvs@apache.org Subject: cvs commit: jakarta-jetspeed/proposals StateManager.txt X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N ggolden 02/05/03 08:07:40 Modified: proposals StateManager.txt Log: Revised proposal. Introduced the different session types, and new way to access state (from RunData rather than the Portlet API) Revision Changes Path 1.2 +161 -119 jakarta-jetspeed/proposals/StateManager.txt Index: StateManager.txt =================================================================== RCS file: /home/cvs/jakarta-jetspeed/proposals/StateManager.txt,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- StateManager.txt 11 Apr 2002 04:15:43 -0000 1.1 +++ StateManager.txt 3 May 2002 15:07:40 -0000 1.2 @@ -1,159 +1,180 @@ Jetspeed Proposal: StateManager Service -Version: $Revision: 1.1 $ +Version: $Revision: 1.2 $ Proposed by: Glenn R. Golden, University of Michigan (ggolden@umich.edu) -Status: Proposed -Date: April 11, 2002 +Status: Revised Proposal +Date: May 1, 2002 +Revision 1.2 Note +================= + +This is a revisal of the initial (April 11, 2002) StateManager proposal. + +The key change is how state information managed by the StateManager is delivered to the Portlet. Rather than proposing new cover methods for the Portlet API, we introduce new methods in the JetspeedRunData that can be used to access state information. + +Also of importance, the clarification of the concepts of different types of sessions: UserSession, PageSession and PortletSession. Each type of session can have state managed by the StateManagerService. + Overview ======== -This proposes a new Jetspeed service, the "StateManager" service, which helps to manage a certain "scope" of information related to a particular portlet instance's interaction with a particular user. The service would be implemented as a Turbine service with convenience wrappers placed into the Portlet API. Portlets as well as other parts of the portal engine could keep information in this service. +This proposes a new Jetspeed service, the �StateManagerService�, which helps to manage a certain "scope" of state information related to a particular user�s interaction with various parts of Jetspeed. Each type of user interaction is described as being within a �session�; this much like the HTTP session that is maintained by the Servlet container for Jetspeed, but we introduce two new levels of sessions. Each set of state information for each session is independent of all others. -The key difference between what this service provides and what other current mechanisms provide (such as the persistence service, the registry, and the turbine user getTemp/setTemp) is in the scope and lifetime of the information stored within. +The key difference between what this service provides and what current mechanisms (such as the persistence service, the registry, and the turbine user getTemp() / setTemp()) provide is the scope and lifetime of the information stored within. +The StateManagerService, and the SessionState objects, keep attributes for each state. Attributes are named with Strings; the name space of each state is independent of all other states. Attribute values can be any object. -Purpose -======= +SessionState is different from the "customization" of a Portlet, which is permanent, and provides parameters that a Portlet instance uses for all users, stored in the PSML document for the Portal page. -The StateManager service is available to aid in storing transient information used by a portlet, and scoped to each portlet instance's interaction with each user in a specific browser window. We will call this set of information "portlet instance state", or just "state" for short. +State is different from the "configuration" of a Portlet, which is permanent, and provides parameters that a Portlet uses for all users of all instances of the Portlet, stored in the Portlet registry. -A "portlet instance" is a particular placement of a portlet in a particular portal page. +State is different from the getTemp()/setTemp() mechanism in the http session, although it is close. State provides separate namespaces for each Portlet instance, but the temp values provide only a single namespace that must be shared by all Portlets and other uses. -If one portlet is placed twice in the same portal page, or placed in two different portal pages, making multiple portlet instances, different states would be kept for each instance. +One approach that developers currently use is to store state information in hidden form fields, so that when the user next interacts with the Portlet, the state for that particular user will be read from the form. This approach fails in a Portal environment when the user interacts with some *other* Portlet on the page. The state information hidden in form fields is not present in the form that was submitted, but *all* Portlets must provide content with each request. State must be stored in the Portal engine and made available at any time to the Portlet. -If two different users are viewing the same portlet instance on the same portal page, then different states would be kept for each user, for each portlet instance. -State is transient, and lasts only as long as the user is interacting with the portlet instance, or, at worst, as long as the user's session is active. Once state expires, it is discarded. +SessionState +============ -State is different from the "customization" of a portlet, which provides parameters that a portlet instance uses for all users and is stored in the PSML document for the portal page. +�SessionState� information keeps track of the information necessary to properly render the Portal page or element of the page to the user based on the user�s recent activities in this usage session. At the Page level, the state might include which Pane has been selected by menu or tab to view for this particular user in this particular page in this particular browser window. At the Portlet level, the state might include what transient display options the user has selected this time, so far; or what step of a multi-step Portlet process this particular user is on for this particular page in this particular window. -State is different from the "configuration" of a portlet, which provides parameters that a portlet uses for all users of all instances or the portlet, and is stored in the portlet registry. +SessionState is transient. It begins with a user pointing a browser window at a Jetspeed Portal site, and ends when the user leaves. When the user returns, new state information is collected. -State is different from the getTemp/setTemp mechanism in the http session, although it's close. State provides separate name spaces for each portlet instance, but the temp values provide only a single namespace that must be shared by all portlets and other uses. +The StateManagerService makes sure that expired SessionState is cleaned up. This happens automatically or by explicit requests from the software. -Potential Uses +Session Levels ============== -A portlet would use the portlet instance state to store any information it needs to keep around to produce the proper content for each different user using the portlet in each different portal page. For example, in a "wizard" style portlet, the current step could be stored in the state. Different users using the portlet would naturally be on different steps, so state has the correct scope for this information; the scope of customization or configuration would not work here as it would apply to all users or all portlet instances. +We recognize three different levels of sessions: -In a content management browsing portlet (like a WebDav portlet), the content management system connection information (such as the WebDav url) may be configuration information, shared among all users of that portlet; this may also be customization information, shared by all users of a particular instance of the portlet. But which folder each user is currently viewing is user specific, and portlet instance specific, so must be kept in the portlet instance state. +- �UserSession�: This is one user�s interaction with Jetspeed, and matches the users� HTTP session. -One approach that portlets currently use is to store state information in hidden form fields, so that when the user next interacts with the portlet, the state for that particular user will be read from the form. This approach fails in a portal environment when the user interacts with some *other* portlet on the page. The state information hidden in form fields are not present in the form that was submitted, but *all* portlets must provide content with each request. State must be stored in the portal engine and available at any time to the portlet. Only portlet instance state has the proper scope, makes the proper distinction between different portal instances and different user sessions (and, ideally, different browser windows). +- �PageSession�: This is one user�s interaction with one particular Jetspeed Portal page in a particular browser window. There may be many Page sessions �within� a singe UserSession; one for each browser window the user has open on a Portal page. When a UserSession is over, all PageSessions also end. A PageSession also ends if and when Jetspeed detects that the page is no longer displayed in the user�s browser. +- �PortletSession�: This is one user�s interaction with one particular Jetspeed Portlet placed in a particular location in the layout of a particular Portal page open in a particular browser window. There may be many PortletSessions �within� a single PageSession; one for each Portlet placement in the Portal page (i.e. one for each Portlet instance). All such PortletSessions end when the PageSession (or UserSession) ends. -Portlet Instance State -====================== -To match the format of the configuration and customization information, the state is organized as a set of attributes; name = value pairs. Names are strings, and can be any strings the portlet needs (the name space is separate between different portlet instance states). Values can be any object. +Using the Service +================= -State is never serialized, so the value objects live just in memory. State is cleaned up, either explicitly by the portlet or automatically when the user's interaction session expires. State information will not accumulate on the server past its lifetime. +The StateManagerService works in conjunction with appropriately formed �StateKey� to keep track of this state information. The service is implemented as a Turbine service, and can be found using the Turbine service manager. +A Portlet can access the appropriate PortletSession state for a request by calling a new method in the JetspeedRunData, which forms the proper StateKey and interact with the service to find the proper �SessionState� object. -State Key -========= +Code in the Portal engine parts of Jetspeed can also use the JetspeedRunData to aid in composing an appropriate StateKey and accessing SessionState (for UserSession and PageSession) objects. + + +StateKey +======== + +For a PortletSession state, the StateKey includes the following to achieve our desired scope: +- HTTP session id +- Portal Page id +- Portlet id + +For PageSession state, the StateKey includes all but the Portlet id portion as described above. + +For the UserSession state, the StateKey matches the HTTP Session id. + + +PortletSession Use +================== + +The simple way to use this feature, to give a Portlet the appropriate PortletSession state for this request, involves an addition to the JetspeedRunData object. A Portlet can call: + + public SessionState getPortletSessionState(String id); + +and provide it with the Portlet�s ID (getID()) as the id parameter. This method takes care of forming the proper state key, using another new method in JetspeedRunData: + + public String getPageSessionId(); + +and adding the provided Portlet id. + + +PageSession Use +=============== + +For use within the Portal engine, the PageSession state for the current request can be accessed using the JetspeedRunData as well. Code can call: + + public SessionState getPageSessionState(); -To achieve our desired scope, portlet instance state is keyed by: -- the session id -- the portal page id -- the portlet id -- (and ideally a unique id to distinguish different browser windows on the same portal page in the same user session). +The proper key for the PageSession will be formed. -The key for the state is composed by the service (wrapper). The state key for a portlet can be accessed by the portlet and used for other purposes. -For instance, the state key can be encoded in a portlet's form, so that when the form is being processed, the portlet can ignore any forms that do not have its own unique state key. A state key encoded in a form can enable a turbine action to handle the form, which would not otherwise know what to do with the form fields, since at turbine action processing time, no specific portlet has been identified. +UserSession Use +=============== +For symmetry, we will provide a way to access the UserSession state, although we could instead use the HTTP session directly. JetspeedRunData will also have: -Convenience Wrapper -==================== + public SessionState getUserSessionState(); -A convenience wrapper is built into the Portlet API, since most of the use of the service will be in portlet code. VelocityPortletAction classes have access to the portlet, and can use this same wrapper. Other uses of the service can find the service using the turbine service location methods and make direct calls to it. +The proper key will be formed. -How to use -========== +General Use +=========== -Any Portlet can access the portlet instance state by calling on these new Portlet API methods: +Once the state object is found, it can be used to access and manipulate state values and access the PortletSession key. Here's the proposed SessionState interface (but check with the actual code for current details): +public interface SessionState +{ /** - * Access the named portlet instance state attribute. - * @param name The attribute name, as define by the portlet. - * @param rundata The rundata object for the current request. - * @return The named portlet instance state attribute value. + * Access the named attribute. + * @param name The attribute name. + * @return The named attribute value. */ - public Object getStateAttrbute( String name, RunData rundata ); + public Object getAttribute( String name ); /** - * Set the named portlet instance state attribute value to the provided object. - * @param name The attribute name, as define by the portlet. + * Set the named attribute value to the provided object. + * @param name The attribute name. * @param value The value of the attribute (any object type). - * @param rundata The rundata object for the current request. */ - public void setStateAttribute( String name, Object value, RunData rundata ); + public void setAttribute( String name, Object value ); /** - * Remove the named portlet instance state attribute , if it exists. - * @param name The attribute name, as define by the portlet. - * @param rundata The rundata object for the current request. + * Remove the named attribute, if it exists. + * @param name The attribute name. */ - public void removeStateAttribute( String name, RunData rundata ); + public void removeAttribute( String name ); /** - * Remove all portlet instance state attributes. - * @param rundata The rundata object for the current request. + * Remove all attributes. */ - public void clearState( RunData rundata ); + public void clear(); /** - * Access an iterator on all names of attribute stored in the portlet instance state. - * @param rundata The rundata object for the current request. - * @return An iterator on all names of attribute stored in the portlet instance state. + * Access an iterator on names of all attributes. + * @return An iterator on on names of all attributes. */ - public Iterator getStateAttributeNames( RunData rundata ); + public Iterator getAttributeNames(); /** - * Access the unique portlet instance state key. - * @param rundata The rundata object for the current request. - * @return the unique portlet instance state key. + * Access the StateManager key for this SessionState. + * @return the StateManager key for this SessionState. */ - public String getStateKey( RunData rundata ); - -These additions to the Portlet API are implemented in AbstractPortlet, which forms the appropriate state key for the portlet instance / user session, and provides covers that make calls to the StateManager. + public String getKey(); -For Velocity Portlets, a portlet's processing is done in a VelocityPortletAction class. The routines in this class are provided with a portlet, or can get one easily. These new Portlet API methods can be invoked on this portlet to handle state. +} // interface SessionState The StateManagerService API =========================== -Direct callers of the API can find the manager using code like this: +Direct callers of the API can find the service using code like this: StateManagerService mgr = (StateManagerService)TurbineServices - .getInstance() - .getService(StateManagerService.SERVICE_NAME); - -The calls to the manager are like the Portlet API calls above, except that they take a state key instead of a RunData object. + .getInstance().getService(StateManagerService.SERVICE_NAME); -Here's the StateManager API: +These users must form their own unique state keys. +The calls to the manager are like the SessionState calls above, with the state key as an additional parameter. -// package -package org.apache.jetspeed.services.statemanager; +Here's the proposed StateManagerService API (but check with the actual code for current details): -// imports -import java.util.Iterator; - -import org.apache.turbine.services.Service; - -/** -* A state manager service is... -* @version $Id: StateManager.txt,v 1.1 2002/04/11 04:15:43 taylor Exp $ -*/ public interface StateManagerService - extends Service { - /** The default control to use when none is specified */ + /** The name used to find the service in the service manager. */ public String SERVICE_NAME = "StateManagerService"; /** @@ -192,76 +213,97 @@ */ public Iterator getAttributeNames( String key ); + /** + * Access a SessionState object with the given key + * @param key The SessionState key. + * @return a SessionState object with the given key. + */ + public SessionState getSessionState( String key ); + } // interface StateManagerService +Retiring State +============== + +When the session a state is associated with is ended, the StateManagerService must clean up the old state. This can happen automatically, withing the implementation of the service, and also by explicit request from the software. + +The retireState() method of the service can be called to explicitly cause a set of states to be retired. This would be done if we knew that a PageSession was over, for example. The PageSession id would be passed in; the service would match this id to the PageSession state and all the PortletSession states �within� this PageSession, and clean them all up. Or, if the entire UserSession was known to be over, the UserSession id could be passed to the retireState(), and the UserSession state, and all PageSession and PortletSession states associated with that user session would be cleaned up. + +The automatic method within the service implementation will tie it to the binding out of the HTTP session for the user. If there is any state left in the service for this user session at the HTTP session timeout time, it will be cleaned up. + + +Efficiencies +============ + +The getPortletSessionState(), getPageSessionState() and getUserSessionState() calls in the JetspeedRunData merely forms the appropriate key, find the StateManagerService and asks the service for an SessionState object. This is a "lazy" process; if a caller never asks for the state, no work will be done; once the caller has the SessionState object, accessing state information is delayed until actually called upon. The SessionState object is created and owned by the StateManagerService (it acts as a factory for these objects). SessionState is really a cover to StateManagerService calls with the appropriate key. + + Work List ========= To implement this proposal, the following work must be done: -- Update Portlet API with getStateAttribute, setStateAttribute, removeStateAttribute, clearState, getStateAttributeNames, and getStateKey methods. +1.1) Extend org.apache.jetspeed.services.rundata.JetspeedRunData and the JetspeedRunData implementation org.apache.jetspeed.services.rundata.DefaultJetspeedRunData to add getPortletSessionState(), getPageSessionState(), getUseSessionState(), and getPageSessionId(). -- Update AbstractPortlet API with new Portlet API implementations. +1.2) Add the new StateManager service API interface (called: org.apache.jetspeed.services.statemanager.StateManagerService.java) -- Add a new StateManager service API (called: org.apache.jetspeed.services.statemanager.StateManagerService.java) +1.3) Add the new StateManager service implementation (called: org.apache.jetspeed.services.statemanager.JetspeedStateManagerService.java). The implementation of the SessionState will be a private inner class in the service implementation. -- Add a new StateManager service implementation (called: org.apache.jetspeed.services.statemanager.JetspeedStateManagerService.java) +1.4) Add the new SessionState API interface (called: org.apache.jetspeed.services.statemanager.SessionState.java) -- Update tr.p to include the state manager service. +1.5) Update tr.p to include the state manager service. -- Provide Unit tests of the wrappers and the service. +1.6) Provide Unit tests of the JetspeedStateManagerService and SessionState implementation. -- Provide example portlet (AbstractPortlet and VelocityPortlet) using the state manager features. +1.7) Provide Unit tests for the new JetspeedRunData methods. -- Update PortletWrapper to wrap the new Portlet API methods. +1.8) Provide 2 example Portlets (one AbstractPortlet and one VelocityPortlet) using the StateManagerService / SessionState features. -- Update BasePortletSet with a copy of the new Portlet API implementation from AbstractPortlet. - -- Update ContainerTestPortlet to satisfy the new Portlet API methods. +1.9) Provide a tutorial or docs about using state in Portlet design. Browser Window Distinctions =========================== -If we want to fully support multiple browser windows for one user (in one http session), that all can display the same portal page (perhaps different portlets maximized, different panes selected, or all the same, but with different user interaction state in the portlets), we need to have a unique id for each browser window, know what that id is in the request, and use it as part of our state key. +If we want to fully support multiple browser windows for one user (in one http session), that all can display the same Portal page (perhaps different Portlets maximized, different panes selected, or all the same, but with different user interaction state in the Portlets), we need to: + a) have a unique id for each browser window + b) know what that id is in the request, and + c) use it as part of our state key. + +The browser window information must make its way into the PageSessionId. We will look at ways to do this, but at first this service will not distinguish between different windows. +Additional work for this: -Other uses of StateManagerService -================================= +2.1) Identify individual browser windows and make part of the PageSessionId. -Other than for portlet use, the StateManagerService can manage state for portal page instances, replacing mechanisms currently in place that may not work properly when multiple windows are opened by a user in the same http session (even if they show different portal pages). -A portal page instance is a portal page being viewed by a user in a browser window. Different users viewing the same portal page view different portal page instances. +Portal Engine of StateManager +============================= -State can be managed for each portal page. If two different users are viewing the same portal page, different state would be kept for each user. If a user is viewing two different portal pages, different states would be kept for each portal page. +Current mechanisms used to manage PageSession state may not work properly when multiple windows are opened by a user in the same http session (even if they show different Portal pages). We can change Jetspeed to use the StateManagerService and PageSession state to correct this. -The key used for portal page instance state would be -- the session id -- the portal page id -- (and ideally a unique id to distinguish different browser windows on the same portal page in the same user session). +PageSession state properly distinguishes between two different users viewing the same Portal page, as well as between two different Portal pages being viewed by the same user in the HTTP session. -Once we establish portal page state, we can use it to store information we want to keep a) separate for each portal page instance, and b) transient for the user session only. +The following areas of Jetspeed could be converted to use the StateManagerService and PageSession state: -Maximize: When a users maximizes a portlet, this should not effect other users, nor should it effect other browser windows the maximizing user has open on the same or other portal pages. Same for when the user restores. +Maximize: When a users maximizes and restores a Portlet, this should not affect other users, nor should it affect other browser windows the user has open on the same or other Portal pages. The PageSession state could include the Portlet ID of the Portlet to display maximized. -When a user maximizes a portlet, this portlet should be displayed full screen whenever this portal page instance gets a request, but only for this particular instance of the portal page. We can store the portlet id of the maximized portlet in the portal page instance state. +Customize: The stack of Portal elements being customized can be stored in the PageSession state. -Customize: The stack of portal elements being customized can be stored in the portal page instance state. +Minimized: When a user minimizes a Portlet, this should not affect other users, and it should be transient, so that next time the user visits the page the minimized Portlet is displayed normally. The PageSession state can include a list of Portal Elements to display minimized. -Minimized: When a user minimizes a portlet, this should not effect other users! Nor should it be remembered so that next time in the portlet is still minimized. This is best stored in portal page instance state. +Panes: When a Portal page has many panes, only one is displayed at a time. The one displayed for one user should be independent of the one displayed for another user, and this need not be remembered next time the user views the Portal page. This can be stored in the PageSession state. -Panes: When a portal page has many panes, only one is displayed at a time. The one displayed for one user should be independent of the one displayed for another user, and this need not be remembered next time the user views the portal page. This can be stored in the portal page instance state. +This work (summarized below) is made possible by this StateManager proposed , but is not part of nor required for this proposal. -This work (summarized below) is made possible by the state manager proposed herein, but is not part of nor required for this proposal. +Additional work for this: -Additional Work List -==================== +3.1) change maximize handling to use PageSession state. +3.2) change restore handling to use PageSession state. +3.3) change minimize handling to use PageSession state. +3.4) change customizer stack handling to use PageSession state. +3.5) change the pane-to-display mechanize to use the PageSession state. -- change maximize handling to use portal page instance state -- change restore handling to use portal page instance state -- change minimize handling to use portal page instance state -- change customizer stack handling to use portal page instance state -- change the pane-to-display mechanize to use the portal page instance state -- To unsubscribe, e-mail: For additional commands, e-mail: