Multiple-page browser support
To support multiple browser pages, web applications must be designed so that the server is aware of the page identifiers and can store contextual data separately for each browser page.
Describes how a JViews web application keeps track of requests from each page of a web browser with multiple pages connected to the same application session.
Describes how to enable the page identifier feature for
JViews Diagrammer web applications, and how to use the feature with the tag library and request beans.
Multiple-page support architecture
When you enable the JViews page identifier feature, JViews can track every page request, linking it with the submitting web page for the duration of the application session. To enable the page identifier feature, see
Designing web applications for multiple browser pages.
The following figure shows two pages (Page<A> and Page<B>) that share the same session object and bean. All contextual data is page-dependent and is stored separately:
Although conceptual requirements for multiple-page support are relatively simple (contextual data must be stored separately), the application server is not able to identify different browser pages merely by inspecting HTTP request headers, because web browsers do not uniquely identify their tabs and windows. Without any browser-specific cues, the web application must implement a technique to track the pages and store the contextual data accordingly.
JViews implements a technique that combines its custom JSF components, JavaScript library, and image servlets to create and maintain an internal identifier for every web page, independent of the originating browser. The identifier is sent to the browser when its associated page is first loaded, and then transmitted back to the server in the form of a request parameter.
The following figure illustrates how the page identifier ( Page-Id ) is sent to the browser along with the server response to the first request:
Once in the web page (Page<B> in the figure), the page identifier ( Page-Id ) is sent back to the server as a parameter of every request, allowing the server to properly identify the page from which the request is coming. The page identifier is used by the server to retrieve the contextual data from the session or other storage area.
The following figure illustrates how the page identifier ( Page-Id ) is sent to the server along with other request parameters:
The session expires only when the browser is no longer active.
Designing web applications for multiple browser pages
In conventional web browsers without tab support, each browser instance has a single page. Each browser page is associated with its own session object while connected to a web application running on a web server. In this case, the conversational state between client and server (contextual data) stored in the session belongs to a single page. In addition to session attributes and resources, this also includes any stateful session beans.
In web browsers with multiple tabs and windows, all pages that connect to the same web application share the same session object and beans. This requires the server to keep track of every page and store the contextual data for each page separately. In general, when handling a request for multiple page support, a web application must use page identifiers to access contextual data from the session or any other available storage area. Managed beans also require special attention; stateful session beans must use the page identifier to access the current state for each page.
However, web applications designed to work with a single page per session do not automatically support multiple page identifiers. When you enable the page identifier feature in JViews, you can design and run web applications that handle browser instances with multiple tabs or pages.
Enabling the JViews page identifier
The JViews page identifier feature is disabled by default. You enable JViews page identifiers by setting the context parameter ilog.views.faces.PAGEID_SUPPORT to true in the web.xml file:
<context-param>
<param-name>ilog.views.faces.PAGEID_SUPPORT</param-name>
<param-value>true</param-value>
</context-param>
Any value other than true disables this feature.
Multiple-page support on the server side
Once enabled, the JViews page identifier feature automatically detects and tracks all pages accessing the web application by checking the request for the IlvServletPageIdUtil.PAGE_ID parameter (jviewsPageId). If no such request is found, JViews considers the request to be coming from a new page and creates a new identifier for it.
The web application must then check for the page identifier to create and store any contextual data (data files and data sources, selection state, the IlvManagerView instance, and so on).
The following public API methods are available to retrieve the page identifier in a JSF application:
IlvFacesPageIdUtil.getPageId() returns the page identifier associated with the current request. A new identifier is created if none exists. This method must be invoked whenever the page identifier is required.
IlvFacesPageIdUtil.setSessionAttributeWithPageId(String,Object) stores an attribute for the session by appending the current page identifier to the given user key. This method must be invoked when storing page-specific data (contextual data) in the session.
IlvFacesPageIdUtil.getSessionAttributeWithPageId(String) retrieves an attribute from the session based on the user key and the current page identifier. This method must be invoked when retrieving page-specific data (contextual data) from the session.
The following public API methods are available to retrieve the page identifier in a non-JSF page:
IlvServletPageIdUtil.getPageId(HttpServletRequest) returns the page identifier from the given HTTP request. A new identifier is created if none exists. This method must be invoked whenever the page identifier is required.
IlvServletPageIdUtil.setSessionAttributeWithPageId(HttpServletRequest,String,Object) stores an attribute for the session associated with the given HTTP request, appending the current page identifier to the given user key. This method must be invoked when storing page-specific data (contextual data) in the session.
IlvServletPageIdUtil.getSessionAttributeWithPageId(HttpServletRequest,String) retrieves an attribute from the session associated with the given HTTP request, based on the user key and the current page identifier. This method must be invoked when retrieving page-specific data (contextual data) from the session.
These API methods enable access to the JViews page identifier feature and provide a way to store and retrieve session attributes that are uniquely assigned to a browser page.
Multiple-page support on the client side
The page identifier is stored on the client side and submitted to the server as a parameter (jviewsPageId) of every HTTP request.
The JViews JavaScript library provides the following API method to access the page identifier on the client side:
IlvPageId.instance.getPageId() returns the page identifier. This method must be invoked whenever the page identifier is required on the client side.
Normally this method is not needed, but if the web application implements JavaScript routines that submit HTTP requests to the server, you must ensure that these requests include a jviewsPageId parameter with the page identifier. Requests from additional form tags must also include this parameter when submitted.
Declaring a JViews Diagrammer component using the tag library
Consider the following DiagrammerView component declaration:
<h:form id="form">
<jvdf:diagrammerView id="diagrammer"
style="width:500px;height:300px"
data="/data/project.idpr" />
</h:form>
In the above example, the DiagrammerView component is not associated with any managed bean. In this scenario, JViews automatically stores the page contextual data (IlvDiagrammer and the project.idpr data file). When the JViews Diagrammer JSF component is declared in this way, it will support multiple browser pages automatically.
Associating a managed bean to the DiagrammerView data attribute
The following example associates the data tag attribute of the DiagrammerView with the dataSource property of the dataBean bean:
<h:form id="form">
<jvdf:diagrammerView id="diagrammer"
style="width:500px;height:300px"
data="#{dataBean.dataSource}" />
</h:form>
In this case, JViews automatically stores the corresponding IlvDiagrammer instance according to the page identifier,but you must ensure that the managed bean (dataBean) does the same for the dataSource property. You can do this by converting it to a request bean that creates or retrieves the data source from the session, as follows:
// Holds the data source in the request bean
private IlvDiagrammerDataSource dataSource = null;
// The constructor tries to fetch the data source from the session,
// creating a new one if needed
public DataBean() {
// Try to retrieve the data source from the session
dataSource = (IlvDiagrammerDataSource)IlvFacesPageIdUtil.getSessionAttributeWithPageId("dataSource");
if (null == dataSource) {
// Data source not found in session, create a new one and then store it
dataSource = createDataSource();
IlvFacesPageIdUtil.setSessionAttributeWithPageId("dataSource", dataSource);
}
}
// The getter just returns the data source reference
public IlvDiagrammerDataSource getDataSource() {
return dataSource;
}
The code snippet shows a possible request bean implementation where the getter method (getDataSource) uses the IlvFacesPageIdUtil API to persist the data source object in the session object. IlvFacesPageIdUtil relies on the page identifier to determine the page from which the request is submitted. Although this example describes the data tag attribute, the solution can be used for other tag attributes as well.
Binding a managed bean to the DiagrammerView tag
The following example illustrates how to bind the DiagrammerView to a managed bean. In this scenario you must ensure that the DiagrammerView instance is properly stored per browser page:
<h:form id="form">
<jvdf:diagrammerView binding="#{dataBean.diagrammerView}"
id="diagrammer" style="width:750px; height:350px"
</h:form>
As described in the previous example, the dataBean bean is converted to a request bean that is capable of retrieving the DiagrammerView instance from the session, using the page identifier:
// Holds the JViews Diagrammer JSF component in the request bean
private IlvFacesDiagrammerView diagrammer = null;
// The constructor tries to fetch the JViews Diagrammer JSF component
// from the session, creating a new one if needed
public DataBean() {
// Try to retrieve the JViews Diagrammer JSF component from the session
diagrammer = (IlvFacesDiagrammerView)IlvFacesPageIdUtil.getSessionAttributeWithPageId("diagrammer");
if (null == diagrammer) {
// JViews Diagrammer JSF component not found in session,
// create a new one and then store it
diagrammer = new IlvFacesDHTMLDiagrammerView();
IlvFacesPageIdUtil.setSessionAttributeWithPageId("diagrammer", diagrammer);
}
}
// The getter just returns the component reference
public IlvFacesDiagrammerView getDiagrammerView() {
return diagrammer;
}
// The setter can be ignored because the bean relies on the session
// to retrieve the component
public void setDiagrammerView(IlvFacesDiagrammerView diagrammerView) {
// does nothing
}
Copyright © 2018, Rogue Wave Software, Inc. All Rights Reserved.