Skip Headers
Oracle® Fusion Middleware Portlet Development Guide for Oracle WebLogic Portal
10g Release 3 (10.3.6)

Part Number E14244-06
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

8 Working With JSF-Java Portlets

This chapter discusses procedures and best practices for developing and configuring JSF portlets within a JSR-286 (Java 2.0) portlet using the Standard JSF Bridge (JSR-329). For using the WLP native JSF bridge, see

This chapter includes the following sections:

8.1 Overview

In a portal environment, an application implemented using Java Server Faces technology can be surfaced as a portlet by creating a JSF portlet. Oracle WebLogic Portal has supported the use of JSF for the implementation of portlets by developing the WLP native bridge since a standards-based bridge did not exist. Starting in WLP 10.3.2, the support for JSF portlets continues to be enhanced with the added support for the JSR-329 standards-based JSF bridge. The new JSR-329 bridge is now the default for JSF portlets which continues to leverage all of the powerful features of WLP.

This section includes the following topics:

8.1.1 Supported Portlet Bridges

The standard JSR-286 portlet with the standard JSR-329 compliant bridge is new in WLP 10.3.2 and allows for JSF portlets to interoperate consistently across all Java portlet (JSR-286) compliant containers. This type of JSF portlet is now the default.

Note:

For detailed information about Java portlet features supported by WLP, see Chapter 6, "Building Java Portlets."

WLP continues to provide a native JSF portlet bridge implementation for use in web applications that are configured to use JSF 1.1 and/or the Facelet facet. This option creates a JSP-style portlet with a <facesContent> XML element, which uses the native bridge functionality. In other words, a portlet with a <facesContent> element uses the WLP native JSF bridge. To add the Facelet facet, see the section "Portal Web Project Wizard" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal, which includes instructions on how to add and remove facets. The Portal Web Project Wizard does not let you configure JSF 1.2 with Facelets, so you must choose JSF 1.1.

Note:

Before WLP 10.3.2, the native JSF portlet bridge was the only JSF portlet bridge available in WebLogic Portal. If you are developing a new project, Oracle recommends that you avoid using the native JSF bridge because it is less likely to be compatible with third-party JSF toolkits.

The Portlet Creation Wizard automatically detects the version of JSF that is used in a web application and provides the correct portlet type for you to select. When JSF 1.2 is the configured version, the JSF portlets use Java Portlet 2.0 (JSR-286) with the JSR-329 standard portlet bridge. When JSF 1.1 is the configured version, the WLP native portlet bridge is used.

Table 8-1 summarizes the types of portlets that are created depending on the version of JSF you are using. As a developer, it is important to know what kind of portlet is created. For instance, a standard Java 2.0 (JSR-286) portlet has many characteristics that do not pertain to the native Faces Content Portlet. The type of portlet created can affect development choices, like interportlet communication, event handling, and portlet preferences.

Table 8-1 Resulting Portlet Types for JSF Portlets

JSF Version Facelet Facet Added to Project Type of Portlet Created Portlet Bridge Used Comments

1.1

N/A

Faces Content Portlet

Native WLP Bridge (non-standard)

JSF 1.1 always uses the WLP native bridge

1.2

Yes

Faces Content Portlet

Native WLP Bridge (non-standard)

 

1.2

No

Java Portlet Version 2.0 (JSR-286)

JSR-329 Bridge (standard)

 

The version of JSF is configured in the web application as a facet. For more information on facets, see the section "Adding Facets to an Existing Web Project" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

The remaining of this chapter describes configuration and architecture of Java 2.0 portlets using JSF 1.2 and the JSR-329 standard bridge.

8.2 Creating Java 2.0-JSF 1.2 Portlets

For detailed information on creating a Java-JSF standard portlet using the Oracle Enterprise Pack for Eclipse, see Section 5.4.2, "Building JSF Portlets." At this point you should have your first Java-JSF portlet created. The artifacts are as follows:

8.3 JSR-286 and JSR-329 Architecture

The portlet bridge acts as the translation engine between the portlet environment and the Faces environment. A portlet is an application that provides a specific piece of content (for example, HTML, XHTML, WML) to be included as part of a larger picture called a portal page. A Faces portlet uses the Faces design paradigm within a Java portlet paradigm. The bridge allows for the blending of the Java portlet lifecycle with that of Faces lifecycle.

Reading the JSR-329 spec combined with the JSR-286 spec will greatly improve your understanding about the JSR-286 and JSR-329 architecture. The following are the salient features of the architecture:

The javax.portlet.faces.GenericFacesPortlet in JSR-329 extends javax.portlet.GenericPortlet from the JSR-286 specification. A portlet developer may often want to extend GenericFacesPortlet to handle special init or destroy processing or override any of the interface methods to implement custom behavior before calling into the Faces bridge. The GenericFacesPortlet overrides the init, destroy, doDispatch, doEdit, doHelp, doView, processAction and processEvent methods of GenericPortlet and defines several new methods to handle JSF processing.

Chapter 5, "Bridge Request Lifecycle Requirements" of the JSR-329 specification at http://www.jcp.org/en/jsr/detail?id=329 explains the portlet lifecycle combined with the Faces lifecycle in more detail. The high-level summary is that the portlet enters its lifecycle when the client (typically a browser) generates a request (HttpRequest) to display or interact with the web page which contains the portlet. The portlet is then asked to render, process an action, process a given event, or serve a resource based on that client request. Note that when processing an action or an event, these may trigger more events before a render is completed. In a Faces portlet, these portlet lifecycles must be coordinated to the Faces system of invoking the managed bean, processing validations, handling error messages, rendering its components, and processing the navigation rules. To handle the coordination of these two different lifecycles is the purpose of the JSR-329 bridge.

Each JSF-Java portlet on the page gets its own instance of the bridge. By default, each JSF-Java portlet created through the Eclipse IDE uses the base class of the GenericFacesPortlet. Keep in mind that the portlet container and the Faces engine are loosely coupled through the portlet bridge. That is, they are not directly tied to each other. They can communicate indirectly via the underlying request (HttpRequest) from the client (browser).

The biggest challenge and source of confusion for a Java-JSF portlet developer is the fact that Faces has a single request model that is split between action and rendering. The Java portlet model has a multi-request lifecycle split between action and/or event and rendering. In addition, in the Java portlet 2.0 model, the action process can spawn one or more events before issuing a render request. The JSR-329 bridge manages this complexity, but it is also important for the developer to understand the phases to help aid in writing the appropriate code in the appropriate places for best results.

8.4 Understanding WLP and JSF Rendering Life Cycles

This section explains WLP and JSF rendering life cycles:

8.4.1 WLP and JSF Life Cycles

Both WebLogic Portal and JSF frameworks support the concept of component trees that define the rendering of the HTML page. Both also rely on the concept of rendering life cycles. Each component tree is traversed multiple times during the execution of the request. Each traversal is called a life cycle or phase.

When developing JSF portlets, it is helpful to understand how those life cycles interact. For more information on the phases of the portal life cycle, see Chapter 4, "Understanding Portlet Development" in the Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

8.4.2 Invocation Order of WLP and JSF Life Cycle Methods

The following represents the merged life cycle execution order across the Portal, Java Portlet, and JSF containers:

  • On portal app deploy

    • PortalContainer:init

    • GenericFacesPortlet.init()

  • On portal app undeploy

    • PortalContainer:destroy

    • GenericFacesPortlet.destroy()

  • PortalContainer:preRender

  • PortalContainer:render

    • GenericFacesPortlet.doView and/or GenericFacesPortlet.serveResource

    • JSFContainer:RestoreView (only on first render of portlet instance)

    • JSFContainer:RenderResponse

  • Portlet link or form submit processing a Portlet.actionUrl

    • GenericFacesPortlet.processAction

    Then, if a JSF file is the view:

    • JSFContainer:RestoreView

    • JSFContainer:ApplyRequestValues

    • JSFContainer:ProcessValidations

    • JSFContainer:UpdateModelValues

    • JSFContainer:InvokeApplication

      • JSFContainer:invoke Action Listeners

      • JSFContainer:invoke Action method

  • PortalContainer:raiseEvents / JSR-286 Events

    • GenericFacesPortlet.processEvent() or annotated event method

    • JSFContainer:RestoreView

Note:

Unlike for a native JSF portlet, a backing file for Java 2.0 portlet is typically unnecessary since the portlet is already based on a Java portlet lifecycle paradigm of init, processAction, processEvent, render, serveResource, destroy. These lifecycles allow you to implement your backing code into the appropriate Java method in your Java portlet. However, it is possible to add a backing file to the portlet to handle certain limited situations, such as the need to have code process in the preRender phase of the portlet since the Java portlet lifecycle does not have a one to one mapping of this lifecycle phase. See Section 8.9, "Converting Native JSF Portlets to Standard Java JSF Portlets."

8.5 Accessing WLP Context Objects from JSF Managed Beans

To enable portlets to programmatically interact with the portal framework, a set of context objects is available from the JSF managed bean.

Table 8-2 shows what portlet context objects are in scope for different managed bean methods for different JSF life cycles. This chart is useful when implementing a managed bean that needs to obtain WLP context information. The key point is that property getters and setters need to be coded so that they work properly with either context object since they may be called during either an action or a render phase. Generally, the PortletPresentationContext is only available during render, and the PortletBackingContext is only available while processing an action.

Table 8-2 Scope of Portlet Context Objects

JSF Life Cycle Managed Bean Method Portlet Backing Context Portlet Presentation Context Portal Use Case

PROCESS_VALIDACTIONS

get property

Yes

No

Portlet receives a postback, input is being validated.

PROCESS_VALIDACTIONS

set property

Yes

No

Portlet receives a postback, input is being validated.

UPDATE_MODEL_VALUES

set property

Yes

No

Portlet receives a postback, input has been validated.

INVOKE_APPLICATION

action method

Yes

No

Portlet is the target of a postback.

RENDER_RESPONSE

get property

No

Yes

Portlet is being rendered.

RENDER_RESPONSE

set property

No

Yes

Portlet is being rendered.


8.6 Understanding Scopes and JSF Portlets

This chapter covers scoping topics that apply to JSF portlets.

8.6.1 Conceptual Scopes for Standard JSF Applications

The standard JSF scopes are interpreted differently in a portal environment. This section discusses the differences and includes the following:

8.6.1.1 JSF Standard Scopes

JSF managed beans have well-defined scopes in the JSF specification. The JSF 1.2 specification provides three scopes for managed beans:

  • Application - Bean state is accessible by all users in the web application.

  • Session - Bean state is accessible to any view for the given user, across the life span of all requests within the session.

  • Request - Bean state is accessible for the duration of a single request.

In addition to these, several other scopes exist. Specifically, JSF 2.0 adds a View scope, and many web frameworks provide a Pageflow scope, as described below. However, these are not supported in JSF 1.2.

8.6.1.2 View Scope

View scope is included in the JSF 2.0 specification. It enables managed beans to be attached to a specific view across multiple HTTP requests. Once a user navigates to a different view, the bean state is destroyed. This is a helpful pattern for scoping state to a single instance of a view for a user, but is not supported in JSF 1.2.

8.6.1.3 Pageflow/Conversation Scope

A Pageflow (also called a conversation) is a subset of the views and controller logic within a web application that pertains to a logical task or business process. Multiple pageflows can exist within a web application, and each one usually carries state that should only be scoped to that pageflow. With Pageflow scope, managed bean state is accessible across the life span of all requests within the session, limited to the time in which a user is interacting with the set of views within that Pageflow. This is not supported in JSF 1.2.

8.6.2 Conceptual Scopes for Portal Applications

Because of the composite nature of a portal user interface, there are more conceptual scopes for portals than for standard JSF applications.

The list of portal scopes includes:

  • Application - Bean state is accessible by all users in the web application.

  • Global Session - Bean state is accessible to any portlet for the given user, across the life span of all requests within the web application.

  • Portlet Group Session - Bean state is accessible to any view within a group of portlet instances or definitions for the given user, across the life span of all requests within the web application. This use case can be important for interportlet communication.

  • Portlet Instance Session - Bean state is accessible to any view within a single portlet instance for the given user, across the life span of all requests within the web application.

  • Pageflow - Bean state is accessible to any view within a Pageflow within a single portlet instance for the given user, across the life span of all requests within the Pageflow. This is not supported in JSF 1.2.

  • View - Bean state is accessible for as long as the user is interacting with the current view across multiple requests within a single portlet instance. If the user is interacting with another portlet, the bean state is retained. This is not supported in JSF 1.2.

  • Portal Aware Request - Bean state is accessible with the portlet instance for the duration of a single request. If the user is interacting with another portlet instance, the bean state is retained until the next request in which the user interacts with the portlet.

8.6.3 Implementation Patterns for Portal Scopes

Table 8-3 describes how the standard JSF scopes map to the WLP scopes, and how the unrepresented JSF scopes are supported. These implementation strategies are explained in the following sections.

Table 8-3 Managed Bean Scope Implementation Strategies

Portal Managed Bean Scope Implementation Strategy for JSF Portlets

Application

faces-config.xml scope = application

Global Session

faces-config.xml scope = session, plus custom code

Portlet Group Session

faces-config.xml scope = session, plus custom code

Portlet Instance Session

faces-config.xml scope = session

Pageflow

Use an alternate navigation controller

View

New scope with JSF 2.0 (not supported in this release)

Portal Aware Request

faces-config.xml scope = request


8.6.4 Reinterpretation of the JSF Session and Request Scopes

Table 8-4 compares JSF managed bean scoping levels between a JSF application and a WLP JSF portlet.

Table 8-4 Comparison of Scoping Levels

Faces-Config.xml Scope Label Conceptual Scope for JSF Application Conceptual Scope for JSF Portlet

Application

Application

Application

Session

Global Session

Portlet Instance Session

Request

HttpRequest

Portal Aware Request


Because a managed bean declared with session scope in faces-config.xml is interpreted as Portlet Instance Session scoped with the portlet bridge, it is possible to put multiple instances of that portlet on a page and not have conflicts. Each portlet instance that uses the managed bean is provisioned with a distinct instance of the bean.

Also, the different interpretation of request scope prevents a JSF portlet from breaking if the user interacts with a second portlet while interacting with the first JSF portlet.

8.6.5 Global Session and Portlet Group Session Scopes

The remaining scopes for managed beans cannot be expressed in faces-config.xml alone. However, the remaining scopes can be achieved using code patterns that involve HttpSession. For details, see Section 8.7, "State Sharing."

8.7 State Sharing

This section includes the following:

8.7.1 State Sharing Concepts

JSF managed beans are intended to be the storage containers for application state within a JSF application. In general, this works well even within a portal environment. However, this standard JSF pattern is not always sufficient. There are cases where state needs to be shared with something outside of the JSF portlet. For example:

  • A different portlet instance's JSF managed bean.

  • A portlet instance in a remote servlet container via WSRP.

  • A non-portal object, such as a servlet or servlet filter.

But, there are limitations that must be heeded when working within the JSF container:

  • A JSF managed bean may not invoke any method on any portlet instance's backing file or Java portlet code, including its own.

  • A JSF managed bean may not invoke any method on a JSF managed bean in another portlet instance.

  • A portlet backing file or Java portlet code may not invoke any method on any portlet instance's JSF managed bean.

Despite these limitations, there are ways to handle these types of situations as explained in the remaining of this section.

8.7.2 State Sharing Patterns

This section includes the following subsections:

8.7.2.1 HttpSession Versus HttpServletRequest

This section includes the following:

8.7.2.1.1 Store state in the HttpSession

In a portal environment, the lifecycle of the request is not always straightforward for the following reasons:

  • WSRP can involve multiple requests - When a user interacts with a portlet which is being consumed over WSRP, the handling of that interaction and the render of the portlet can occur over two requests (performBlockingInteraction and getMarkup requests). Attributes set during the interaction are not available in the subsequent getMarkup request. In this case, storing state inside an HttpServletRequest will not behave appropriately.

  • JSR-286 can have multiple request phases as well, for example, first the action request, and/or event request phase, and then a subsequent render request phase.

  • Scoped requests - A portlet in which a code is executed often does not have access to the actual HttpServletRequest. Usually, the portlet is a scoped object. The portlet often does not have access to the actual HttpServletRequest during code execution. Usually the HttpServletRequest is a scoped object of the lifecycle phase and attributes set on a scoped request are not visible to other portlets. This makes sharing state between portlets unfeasible using the request object.

Therefore, it is often preferred to set the state in the HttpSession and there are JSR-286 mechanisms (Single Portlet Pattern and Multiple Portlet Pattern) that can help you. However, storing state in HttpSession has some drawbacks:

  • Attributes set into the HttpSession must be Serializable so that the session can be replicated within a cluster. Not all Java objects are easily serializable, so this may be an issue. One way around this issue is to mark that Java object as transient.

  • WebLogic Server distributes or stores the attributes by serializing the attributes. Adding more attributes to the HttpSession creates higher overhead for the replication facility. Again it could be that you won't need this attribute replicated, and therefore, could mark the Java object that is being stored as an attribute as transient to avoid this replication overhead, since transient objects are not serialized.

  • If an attribute is appropriate only for the current request, the HttpSession attribute must be removed by the managed bean after it is finished with it.

  • When used for multiple portlet patterns, the approach is fragile. This is discussed in more detail in Section 8.7.2.3, "Multiple Portlet Pattern."

8.7.2.2 Single Portlet Pattern

This pattern is defined as sharing state amongst components of a single portlet instance with other components affiliated with that portlet instance, for example, the Java Portlet itself and corresponding JSF managed bean. In the case of single pattern, the state can--depending on the data structure of the state--be passed through as response render parameters or be stored as request attributes. The best namespace for setting attributes is using the portlet's instance label so that if the same portlet exists in more than one location in a portal, its attributes are not mixed. These portlet components have access to the portlet instance label.

The javax.portlet.actionScopedRequestAttributes container runtime option handles the request attributes for you, so when they are set, they can be seen in the next lifecycle phase. See Section 6.11, "Using Container Runtime Options" for more details.

8.7.2.3 Multiple Portlet Pattern

Often, it is necessary to have multiple portlets share data between them. Although it seems intuitive to store this data in the HttpSession object as well, it is not recommended because the order in which the portlets get and set the state cannot be predicted. Therefore, HttpSession object should not be used to store data when users are allowed to move portlets on a page. This limitation applies to WSRP environment as well.

Oracle recommends using JSR-286 events or JSR-286 public render parameters for this use case. The major benefits of events and public render parameters are:

  • Layout independent

  • Support for WSRP environments

  • Designed into the JSR-286 portlet architecture. The JSR-286 specification has implemented Public Render Parameters with the intent on sharing view states across portlets. In addition, the specification introduced the JSR-286 events with payloads to enable reacting to state changes. Events add more flexibility, but can cause extra overhead.

8.8 Using JSF in Java Portlets

You are now familiar with the general architecture. This section focuses on the coding details of common situations a portlet developer needs to know when writing the portlet.

It will be helpful if you already have an understanding of the two specifications: JSR-286 for the Java portlet architecture and JSR-329 for the JSF bridge architecture.

javax.faces.context.ExternalContext, as described in the JSF documentation "contains all of the per-request state information related to the processing of a single JavaServer Faces request, and the rendering of the corresponding response." It is here where you will be able to access the PortletRequest and PortletResponse objects.

FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
PortletRequest preq   = ec.getRequest();
PortletResponse presp = ec.getResponse();

In the WLP native JSF bridge, the architecture environment was different, thus, the ExternalContext returned an HttpServletRequest and HttpServletResponse instead. This is a fundamental concept to understand when converting your portal application from using native JSF portlets to JSF-Java portlets or just writing JSF-Java portlets in general. With Java portlets, there is another layer between the actual HttpServletRequest/HttpServletResponse and the Faces environment. This Java portlet layer provides for a standards-based way to developing your portlet.

The following sections explain in more detail common situations using the PortletRequest/Response and HttpServletRequest/Response objects:

8.8.1 Servlet Request And Servlet Response

Generally the PortletRequest and PortletResponse objects give you the necessary access to the client request and response to do most of your development work. However, there are times when you need access to one layer deeper and need the actual ServletRequest and ServletResponse.

For example, when the ServletAuthentication class on Oracle WebLogic Server is used to acquire an authenticated user session, it requires the ServletRequest and ServletResponse objects. In the native WLP bridge, the following code returned an instance of these objects:

FacesContext fc = FacesContext.getCurrentInstance();
HttpServletRequest req = 
(HttpServletRequest)fc.getExternalContext().getRequest();
HttpServletResponse resp =
 (HttpServletResponse)fc.getExternalContext().getResponse();

This above code gets a ClassCastException when using Java portlets, because now the getExternalContext().getRequest() call returns a PortletRequest and getExternalContext().getResponse() returns a PortletResponse.

In the Java portlet code, it is best to get a handle to the ServletRequest and ServletResponse objects via calling the PortletRequestDispatcher from the PortletContext object that is returned from the facesContext.getExternalContext(), like shown below:

FacesContext fc = FacesContext.getCurrentInstance();
Object obj = fc.getExternalContext().getContext();
if (obj instanceof PortletContext){
   PortletContext pc = (PortletContext) obj;
   PortletRequestDispatcher prdispatcher = 
        pc.getNamedDispatcher("myServletName");

PortletRequestDispatcher enables you to dispatch control to a resource such as a servlet or JSP and provides the servlet or JSP a handle to the ServletRequest and ServletResponse. (In this example a named dispatcher was used, but you can also get an unnamed dispatcher and use a servlet path instead.)

It is also possible to use a non-standard way of accessing the attributes to gain access to the HttpServletRequest and HttpServletResponse like this:

FacesContext fc = FacesContext.getCurrentInstance();
ExternalContext ec = fc.getExternalContext();
PortletRequest portletrequest = ec.getRequest();

portletrequest.getAttribute("javax.servlet.request")
portletrequest.getAttribute("javax.servlet.response")

Although this is possible, it is not recommended because it does not take into consideration the portlet-level scoping of attributes and it is non-standard so it may not work across all portlet containers the same way. However, there are times that dispatching control to a servlet or JSP is overkill and this may be more convenient. But realize that dispatching control to a servlet allows for a more flexible architecture and keeps specialized code inside a servlet and outside of the portlet environment.

See JSFJavaPortletHelper Class in Appendix: JSFJavaPortletHelper for further implementation details.

8.8.2 PortletPreferences

In the WLP native JSF bridge, preferences are handled through the PortletBackingContext, which could be referenced from a backing file. With Java portlets there is a standard API call for getting the PortletPreferences object.

The following code is an example of how to access the PortletPreferences object from within a JSF managed bean method. It acquires the PortletRequest object through which the standard API call of getPreferences() and returns the PortletPreferences object.

FacesContext fc = FacesContext.getCurrentInstance();
PortletRequest pr = (PortletRequest);
fc.getExternalContext().getRequest();
PortletPreferences prefs = pr.getPreferences();

To learn more about PortletPreferences, see Chapter 9, "Developing Portlets."

8.8.3 PortletPresentationContext

The PortletPresentationContext is a WLP class that represents the portal desktop environment. In the WLP native JSF bridge, the JSP file in use typically gets the PortletPresentationContext during the render phase. You can continue to access the PortletPresentationContext through a JSP by dispatching control from your Java portlet to the JSP as described in Section 8.8.1, "Servlet Request And Servlet Response." Doing it this way keeps WLP specific code more isolated.

If you have a need to access the PortletPresentationContext from a JSF managed bean method, you must provide the actual ServletRequest object to the PortletPresentationContext factory object. This technique is shown in the JSFJavaPortletHelper Class example.

8.8.4 Using JSPs in JSF Portlets

In a Java portlet, you can use simple JSP pages that do not contain Faces component tags. These pages behave like a basic Java portlet and are processed without going through the Faces bridge. Using non-Faces component JSP pages may be preferred in some cases such as handing file upload, since the JSF 1.1 and JSF 1.2 implementations did not include a JSF component for this common web use case. See Section 8.14, "Code Examples for Common Use Cases" for an example.

8.9 Converting Native JSF Portlets to Standard Java JSF Portlets

For the most part, the JSF views that worked in the WLP native JSF bridge should continue to work in a Java portlet using the JSR-329 standards bridge. However, there are some differences that you should take into account when converting from the Native JSF Portlets in the Standard Java JSF Portlets.

This section includes the following:

8.9.1 Backing Files

If you used backing files in your native JSF portlets, then Oracle recommends moving the source code that was in there to the appropriate Java portlet methods. Although, there is not a complete one-to-one correspondence with the backing file lifecycle and the portlet lifecycle, it is possible, with the use of events, to create similar behavior. This will help reduce complexity of your portlet code.

To do this, you will want to subclass the GenericFacesPortlet class.

Example 8-2 GenericFacesPortlet

public class MyCustomPortlet extends GenericFacesPortlet {
      @Override
      public void processAction(ActionRequest actionRequest, ActionResponse
      actionResponse)
      {      //code from the backing file's handlePostBackData() method goes here
      super.processAction(actionRequest, actionResponse);
       }
      @Override
      public void init()
      {
      /*code to execute when the portlet is first initialized. Note this has
      different timing than a backing file init() method.
     */
          super.init();
      }
      @Override
public void destroy()
        {
/*code to execute when the portlet is destroyed. Note this has different timing than a backing file destroy() method.
*/
          super.destroy();
      }

Example 8-3 Changing entry in portlet.xml

<portlet>
      <portlet-name>MySpecialPortlet</portlet-name>
      <portlet-class>oracle.samples.wlp.jsf.portlets.MyCustomPortlet
      </portlet-class>
      <init-param>
         <name>javax.portlet.faces.defaultViewId.view</name>
         <value>/demo/display.jsp</value>
      </init-param>
      <supports>
         <mime-type>text/html</mime-type>
         <portlet-mode>view</portlet-mode>
      </supports>
</portlet>

Please note the following differences in the lifecycle between the backing file methods and the Java portlet methods:

  • Backingfile.handlePostBackData() - this is always called, even if the portlet is not the target.

  • MyCustomPortlet.processAction() - this is only called if the portlet is the target.

If code existed in your backing file's handlePostBackData() method that always needs to be executed, then in a Java portlet paradigm, the portlet should subscribe to the appropriate event for your situation.

For example, the portal OnRefresh event is sent to all portlets that are about to be rendered as well as after a processAction has occurred. So, listening for this event in your subclassed Java portlet would be recommended in order to handle setting visibility if that setting of visibility was something that was in the handlePostbackData() method of the backing file. Review the portal events in the section "Event Types" of Oracle Fusion Middleware Portlet Development Guide for Oracle WebLogic Portal for more information on the types of events available to you.

8.9.2 NamingContainer

For the JSF-JSP files used in the JSF Native Portlets, remove all references to the WLP's <jsf-naming:namingContainer>. This is because JSR-329 has its own way of handling namespacing; using WLP's namespacing causes errors in a Java based JSF Portlet.

8.9.3 Events

Convert the WLP proprietary events to the standards-based Java Portlet events model that is new in JSR-286. See Section 12.4, "Portlet Event Handling" for further details.

See Section 12.3, "Differences Between Portal Events and Java Portlet Events" for more details on how to access portal events within your Java Portlet.

8.9.4 Preferences

If using preferences, change how the PortletPreference object is obtained by using the Java Portlet API supplied in the PortletRequest object.

8.9.5 Localization

If using localization, set up the Java Portlet localization for the portlet title.

8.9.6 Error Pages

The native JSF portlet includes an attribute for the error path, which redirects your portlet when an error occurs. See Section 8.10.1.2, "Portlet Error Page" for how to handle errors with Java Portlets.

8.9.7 Portlet Modes

In the JSF native portlets, the help/edit mode .jsp files could not contain any JSF tags, this is no longer the case with Java-JSF portlets. JSF tags may exist in the help or edit or custom modes.

8.9.8 ServletRequest/ServletResponse

If you are using ServletRequest and ServletResponse in your native JSF portlets, you may want to move this code to its own servlet so that it can get a handle to the servletRequest and servletResponse objects. Or, create a helper class to consolidate the coding effort to get the servletRequest and servletResponse from the PortletRequest object. See Section 8.8, "Using JSF in Java Portlets" for further details.

8.10 Using Common WLP Features With JSF Portlets

This section describes how commonly used WebLogic Portal features are used in an environment with JSF portlets.

This section includes the following:

8.10.1 Portlet Container Features

This section discusses the following portlet container features:

8.10.1.1 Portlet Modes

For more information about portlet modes, see Section 9.5.2, "Portlet Modes." Java-JSF Portlets support portlet modes and custom modes just as a Java portlet does. The portlet.xml file identifies which modes it supports and what the defaultViewId should be.

8.10.1.2 Portlet Error Page

A common WLP feature for portlets is the ability to set an error path in the event of an error. This works differently for standard Java portlets. The Java portlet specification requires that the portlet throws a PortletException.Since Java portlet is the underlying technology for the Java-JSF portlet, a PortletException is thrown in the event a portlet cannot process an operation successfully. Therefore, the error page processing is handled in your subclass of GenericFacesPortlet by catching the error in a try/catch block and sending the appropriate error page instead. A more generic approach is to write a portlet filter that watches all responses and handles PortletException in a consistent manner. See Section 6.6, "Portlet Filters" for more details.

In the JSF native portlets, the error page could not contain any JSF tags, this is no longer the case with JSR-286 Faces portlets. JSF tags may exist in the error .jsp file.

8.10.1.3 Portlet Preferences

Portlet preferences provide the primary means of associating application data with portlets. Portlet preferences are accessible through the WLP portlet context objects. For detailed information on portlet preferences in JSR-286 portlets, see Section 9.2.2.3, "Getting and Setting Preferences for Java Portlets Using the Preferences API."

In the context of a JSF portlet, note that after setting preferences values for the portlet, store() must be called. This call is best accomplished by setting preferences in JSF managed bean property setters, and then calling store() in an action method.

To illustrate this technique, consider a JSF portlet that lets a user get a stock quote. The last quote the user obtains is persisted using portlet preferences. The JSF view is shown in Example 8-4. This view retrieves portlet preference values from a JSF managed bean. The managed bean, shown in Example 8-5 sets and gets the preference values from WLP.

Example 8-4 A JSF View

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri='http://bea.com/faces/adapter/tags-naming' prefix='jsf-naming' %>
<f:view>
<h:panelGrid columns="4" width="100%">
<h:form id="stockForm">
    <h:panelGroup>
        <h:outputText value="Stock Quote:"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:inputText id="ticker" value="#{WLPPrefsRequestBean.ticker}"
         required="true"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:inputText id="shares" value="#{WLPPrefsRequestBean.shares}"
         required="true"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:outputText value="#{WLPPrefsRequestBean.currentValue} "/>
    </h:panelGroup>
    <h:panelGroup></h:panelGroup>
    <h:panelGroup></h:panelGroup>
    <h:panelGroup>
        <h:commandButton action="#{WLPPrefsRequestBean.getQuote}"
         id="quote" value="Get Quote"/>
    </h:panelGroup>
    <h:panelGroup>
        <h:commandButton action="#{WLPPrefsRequestBean.resetQuote}"
         id="reset" value="Reset"/>
    </h:panelGroup>
</h:form>
</h:panelGrid>
</f:view>

The managed bean is listed in Example 8-5.

Note:

Example 8-5 uses a utility class described in Section 8.18, "Appendix: JSFJavaPortletHelper."

Example 8-5 The JSF Managed Bean

package oracle.samples.wlp.jsf.beans;
import java.io.Serializable;
import javax.portlet.PortletPreferences;
import oracle.samples.wlp.jsf.JSFJavaPortletHelper;
/**
 * An example that shows how to use WLP preferences with a JSF managed bean.
 * This example makes the following assumptions for the preference writes to work properly:
 *  1. The bean is request scoped
 *  2. The user is authenticated
 *  3. The portal is a streaming desktop, not a .portal
 */
public class WLPPrefsRequestBean implements Serializable {
    private static final long serialVersionUID = 1L;
    private static final String TICKER = "ticker";
    private static final String TICKER_DEF = "ORCL";
    private static final String SHARES = "shares";
    private static final String SHARES_DEF = "1000";
 
    /**
     * The request scoped preferences object.
     */
    private PortletPreferences prefs;
 
    /**
     * Constructor. Initializes the preference object.
     */
    public WLPPrefsRequestBean () {
        prefs = JSFJavaPortletHelper.getPreferencesObject();
    }
 
    // ACTION METHODS
 
    /**
     * Updates the preference values set by the user.
     * @return always null, to retain the same JSF view
     */
    public String getQuote() {
        // all the setting work is done in the setters
        // what is left is to store the new prefs into the database
        JSFJavaPortletHelper.storePreferences(prefs);
        return null;
    }
 
    /**
     * Resets the preferences back to their defaults.
     * @return always null, to retain the same JSF view
     */
    public String resetQuote() {
        JSFJavaPortletHelper.setPreference(prefs, TICKER, TICKER_DEF);
        JSFJavaPortletHelper.setPreference(prefs, SHARES, SHARES_DEF);
        JSFJavaPortletHelper.storePreferences(prefs);
        return null;
    }
 
    // GETTERS AND SETTERS
 
    public String getShares() {
        return JSFJavaPortletHelper.getPreference(prefs, SHARES, SHARES_DEF);
    }
 
    public void setShares(String shares) {
        JSFJavaPortletHelper.setPreference(prefs, SHARES, shares);
    }
 
    public String getTicker() {
        return JSFJavaPortletHelper.getPreference(prefs, TICKER, TICKER_DEF);
    }
 
    public void setTicker(String ticker) {
        JSFJavaPortletHelper.setPreference(prefs, TICKER, ticker);
    }
 
    public int getCurrentValue() {
        // convert the String preference into an integer
        String sharesStr = getShares();
        int shares = 0;
        try { shares = Integer.parseInt(sharesStr); }
        catch (Exception e) {}
        // compute some bogus value
        return shares * 52;
    }
}

8.10.1.4 Portlet Dependencies

JavaScript use is widespread. While it is possible to add Javascript to any portlet, JSF or other types, there are important considerations to think about when introducing Javascript inside your portlet.

The primary concern is the mechanism by which a developer can introduce custom JavaScript into a portlet. While it is certainly possible to inject arbitrary JavaScript using script tags in the <body> or <view> of the page, this causes several problems:

  • It may cause multiple copies of the same JavaScript file to be downloaded.

  • The files are inserted under the BODY element, not the HEAD, which technically is invalid HTML.

  • The JavaScript is not namespaced to an instance, causing potential for collisions of functions and variables between portlets.

WLP provides elegant solutions to these issues. For more information, see Section 9.5.1, "Portlet Dependencies."

While it is important to read that documentation, here is a quick summary of the features:

Portlets can identify which Javascript files (.js files) they depend upon. This dependency is configured by creating a Render Dependencies Configuration file for the portlet. Inside the Javascript files, the Javascript variables and functions can be prefixed with a token "wlp_rewrite_" automatically.

An example of using WLP's Portlet Dependencies feature to inject Javascript inside a portlet in order to perform DOM manipulation can be found in the section "Section 8.10.3, "Ajax Enablement." Another common reason for injecting Javascript inside your portlet is for client-side form validation.

8.10.2 Portal Container Features and JSF Portlets

This section discusses the following portal container features:

8.10.2.1 Locale Provider

WLP provides the ability to implement a LocaleProvider to determine the most appropriate locale for the portal. For more details, see "Section 8.15.5, "Localizing JSF Portlets" in Section 8.15, "Preparing JSF Portlets for Production."

8.10.2.2 Skeleton Files

Skeleton files control the rendering of each component of the WLP page. They are implemented as JSPs. The use of JSF components in these JSPs is not supported. The WLP framework renders the skeletons using standard JSP technology. For more information about skeletons, see the chapter "User Interface Development" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

8.10.3 Ajax Enablement

Many web sites are Ajax enabled to provide a rich user experience. Ajax allows the browser to emulate the interactivity of traditional desktop applications. There are three primary patterns for using Ajax in a portal. This section describes each of those patterns, and explains how to implement the pattern with JSF portlets in WebLogic Portal.

8.10.3.1 Partial Page Rendering Pattern

The Partial Page Rendering (PPR) is the case in which an XmlHttpRequest is issued to the server, and the server responds with visual markup (XHTML or HTML). This markup is written directly into the browser page, updating the content that the user sees. There are several challenges related to this capability:

  • The Ajax request must enter through a proper Portal entry point, so that state such as portlet preferences and previous view state can be honored.

  • It requires the server to be able to return a subset of the markup for the visible page.

  • Some portal-like interactions, like interportlet communication, require the server to respond with more markup than the client expected (e.g. markup for multiple portlets).

Because of these complex issues, WLP supports official techniques for implementing PPR with WLP portlets - Asynchronous Desktop and Asynchronous Portlet modes. These facilities are available to all portlet types, and are transparent to the portlet developer. Thus, any Java-JSF portlet can utilize these facilities without changes to the portlet implementation. These modes are configured using simple configuration settings.

Asynchronous Desktop Mode Asynchronous Desktop mode causes all portlets on the portal to become asynchronous. The WLP framework rewrites all URLs on the portal pages such that they invoke Ajax requests (XMLHttpRequests). This facility supports all WLP framework features, including interportlet communication. This setting is either on or off for the entire desktop.

For more information, see the section "Asynchronous Desktop Rendering" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

Asynchronous Portlet Mode - Ajax or IFrame Asynchronous Portlet mode is similar to Asychronous Desktop mode except that it is configured at the portlet level. This allows more fine-grained configuration of what is Ajax-enabled by the framework. This mode can also be configured to use IFrames instead of Ajax. The primary limitation with this mode is that interportlet communication is not supported.

For more information, see the section "Asynchronous Portlet Content Rendering" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

8.10.3.2 Stateless API Request Pattern

Some use cases work better when the server does not serve up presentation markup, but raw data. In these cases, the client has the necessary code to process that data, and render the presentation markup appropriately. The first type of this pattern is that of a stateless API. Such an API is not specific to the portal or even portlet; it is a general purpose API. In these cases, the XmlHttpRequest must pass all of the necessary information for the server to process the request. The classic example of this type of API is a search box autocomplete API. In this use case, after a user types a character in a search box, and XmlHttpRequest is sent to the server with the contents of the search box. The server responds with a list of possible matches, and JavaScript on the client renders them in a drop down list. Such an API need not be aware of any portal context to fulfill the request. Therefore, any WebLogic Portal portlet (JSF or otherwise) may use such an API without restriction. The Ajax invocation in this case is fulfilled outside the context of the portal environment, and thus there are not any unique issues related to WLP. There are many examples available on the web. Searches for "javascript autocomplete example" will yield many results.

8.10.3.3 Portlet Aware API Request Pattern

The third pattern is for Ajax requests that target data service APIs that have access to the portlet context. The service may need access to the portlet instance's preferences, for example. For these cases, WebLogic Portal's framework must be involved in the request processing. In support of this use case, WebLogic Portal must provide the following:

  • Instancing support - The ability to differentiate which portlet instance on the client issued the request.

  • Context support - The ability to provide portlet instance context, such as its instance label or preferences.

  • IPC awareness - If the Ajax invocation changes the state of the portlet, other portlets might also need to be updated.

WebLogic Portal implements a wrapper for the standard XmlHttpRequest to provide these features. The following example demonstrates its use.

Portlet Aware Data API Example

This example shows how to invoke an API via Ajax that operates within the JSF portlet's context. Meaning, the API implementation has access to portlet instance context such as preferences. The API can return the data in any textual format it chooses, with JSON, XML or simple text being common choices.

The example is shown below. It consists of a simple portlet with just a link. Clicking on the link on the portlet will cause an Ajax request to target a data API implemented in the JSF portlet.

Figure 8-1 A view of the example portlet

Description of Figure 8-1 follows
Description of "Figure 8-1 A view of the example portlet"

  1. Create the JavaScript function that issues the Ajax request using the WLP XmlHttpRequest wrapper. Allow the caller to pass the URL in to the function. A more generic DOM manipulation may be necessary based on URL passed in, but this example is made for ease in understanding. For more information on the use of wlp_rewrite_ token used, see the section "Portlet Dependencies" in Oracle Fusion Middleware Portlet Development Guide for Oracle WebLogic Portal.

    Example 8-6 The JavaScript Function That Invokes the WLP-Specific XMLHttpRequest

    // ajaxPortlet.js
    function wlp_rewrite_issueAjax(dataUrl) {
          var xmlhttp = new bea.wlp.disc.io.XMLHttpRequest();
          xmlhttp.onreadystatechange = function() {
             if ((xmlhttp.readyState == 4) && (xmlhttp.status == 200)) {
                 var data = xmlhttp.responseText;
                // MODIFY: do something with the data here
                 document.getElementById
                   ("wlp_rewrite_xprDiv").innerHTML = data;
             }
          };
          xmlhttp.open('GET', dataUrl, true);
          xmlhttp.send();
    }
    
  2. Create the JSF JSP. The URL that is invoked in the Ajax request is retrieved from a JSF backing bean via the EL expression #{JavaScriptPortletSessionBean.ajaxDataURL}. The backing bean implementation is discussed later. The portlet instance label is prepended to the function due to the use of the wlp_rewrite_ token in the JavaScript file above.

    Example 8-7 The JSF JSP That Triggers the Ajax Call Using an 'onclick' Handler

    <%@ page language="java" contentType="text/html;charset=UTF-8"%>
    <%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
    <%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
    <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>
    <portlet:namespace var="portletns"/>
    
    <f:view>
       <h:form id="ajaxDemoForm">
         <h:outputLink value="#"
           onclick="#{JavaScriptPortletSessionBean.portletInstanceLabel}_issueAjax
            ('#{JavaScriptPortletSessionBean.ajaxDataURL}'); return false;">
              <h:outputText value="Invoke Portlet Data API via Ajax"/>
         </h:outputLink>
         <f:verbatim> <br></br>
         </f:verbatim>
         <div id="<%=portletns%>_xprDiv" style="background-color: #ffcccc;">replace me
         </div>
    
       </h:form>
    </f:view>
    
  3. Implement a JSF managed bean that provides the core logic for implementing the Ajax solution. The getPortletInstanceLabel() method can remain unchanged, but the getAjaxDataURL()method need to be modified to suit your needs. Note the resource Id set here. Remember to add this managed bean to the faces-config.xml file.

    Example 8-8 The JSF managed bean that provides the Ajax data API

    package oracle.samples.wlp.jsf.beans.ajaxdemo;
    import javax.faces.context.FacesContext;
    import javax.portlet.RenderResponse;
    import javax.portlet.ResourceURL;
    import oracle.samples.wlp.jsf.JSFJavaPortletHelper;
    
    /*
     * Demo faces managed bean 
     */
    public class JavaScriptPortletSessionBean {
        ResourceURL ajaxUrl = null;
        // PORTLET INSTANCE LABEL
        public String getPortletInstanceLabel() {
          return JSFJavaPortletHelper.getInstanceLabel();
        }
        // AJAX DATA API URL
        public String getAjaxDataURL() {
          if (ajaxUrl == null){
             RenderResponse rresponse = null;
             FacesContext fc = FacesContext.getCurrentInstance();
             Object obj = fc.getExternalContext().getResponse();
             if (obj instanceof RenderResponse){
                     rresponse = (RenderResponse) obj;
                     ajaxUrl = rresponse.createResourceURL();
                     ajaxUrl.setResourceID("ajax-getData");
                }
            }
            if(ajaxUrl != null) {
              return ajaxUrl.toString();
            }
            else {
                 //throw error here
                 return "error";
            }
        }
    }
    
  4. Create a Java class that extends the GenericFacesPortlet class.

    Example 8-9 The Java Portlet with serveResource Implemented

    package oracle.samples.wlp.jsf.portlets.ajaxdemo;
    import java.io.IOException;
    import javax.portlet.PortletException;
    import javax.portlet.PortletRequestDispatcher;
    import javax.portlet.ResourceRequest;
    import javax.portlet.ResourceResponse;
    import javax.portlet.faces.GenericFacesPortlet;
    public class AjaxEnabledPortlet extends GenericFacesPortlet {
        public void serveResource(ResourceRequest request, ResourceResponse response)
          throws PortletException, IOException{
            String resourceid = request.getResourceID();
            if ("ajax-getData".equals(resourceid)){
            PortletRequestDispatcher prd = null;             
            //demo servlet providing the data service,
            request.setAttribute("dataRqst", "getDemoData");
            prd = getPortletContext().getNamedDispatcher("MyDataService");
            prd.include(request,response);
         }
         else{
              super.serveResource(request, response);
         }
      }
    }
    
  5. Create the portlet dependencies file (.dependencies) to link in the ajaxPortlet.js JavaScript file from above. Note the use of content-uri= in order for wlp_rewrite_ tokens to be rewritten. For more information on creating dependencies files, see the section "Portlet Dependencies" in Oracle Fusion Middleware Portlet Development Guide for Oracle WebLogic Portal.

    Example 8-10 Dependencies Sample

    <?xml version="1.0" encoding="UTF-8"?>
    <p:window 
    xmlns:p="http://www.bea.com/servers/portal/framework/laf/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.bea.com/servers/portal/framework/laf/1.0.0 laf-window-1_0_0.xsd ">
       <p:render-dependencies>
         <p:html>
           <p:scripts>
             <p:search-path>
               <p:path-element>.</p:path-element>
             </p:search-path>
             <p:script type="text/javascript" content-uri="ajaxPortlet.js" />
           </p:scripts>
         </p:html>
       </p:render-dependencies>
    </p:window> 
    
  6. Create the portlet (.portlet file) using the Portlet Wizard (See Section 5.4.2, "Building JSF Portlets"). Use the JSF JSP file created in Step 2 as the "Faces Application URL" in the "Portlet Details" dialog box and enter the path to the dependencies file created in Step 5 in the "Render Dependencies Path" field on "Assign Supporting Files" dialog box while using the Portlet Wizard. (You can also attach or change the dependencies file used by the portlet using the IDE after the portlet has been created.)

    Once the .portlet file is created, open the WEB-INF/portlet.xml file to change the name of the <portlet-class> for the portlet just created, to the class name created in Step 4. In this example that is AjaxEnabledPortlet. This is necessary since the GenericFacesPortlet was subclassed in this example to add custom resource serving.

    Was:

    <portlet>.
    .
    .
        <portlet-class>
         javax.portlet.faces.GenericFacesPortlet
        </portlet-class>
    .
    .
    .
    </portlet>
    

    Change to:

    <portlet>
    .
    .
    .
        <portlet-class>
         oracle.samples.wlp.jsf.portlets.ajaxdemo.AjaxEnabledPortlet
        </portlet-class>
    .
    .
    .
    </portlet>
    
  7. Add the portlet to a portal (.portal file). This portal must have Disc enabled. You can enable Disc in the portal property sheet in the IDE for .portal files, or in the Portal Administration Tool for streaming desktops. For information about how to enable Disc, see http://download.oracle.com/docs/cd/E15919_01/wlp.1032/e14229/disc.htm.

  8. Create the servlet (called MyDataService in Example 8-11) that the portlet dispatches to in its serveResource()method.

    Example 8-11 A Fake DataService Servlet Returning Data for the Request

    package oracle.samples.wlp.jsf.portlets.ajaxdemo;
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    public class MyDataService extends HttpServlet {
        public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                doDataService(request,response);
        }
        public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
                doDataService(request,response);
        }
        
        private String doDataService(HttpServletRequest givenRequest, HttpServletResponse givenResponse){
        // AJAX DATA API SERVICE IMPLEMENTATION
        // Could return any text format, like JSON, XML, simple text
        // Data is hardcoded in this example, but could easily be 
        // accessing a database and be dynamic.
           try {
                 Object attrObj =  givenRequest.getAttribute("dataRqst");
                 if (attrObj != null) {
                    String attr = (String) attrObj;
                    if (attr.equals("getDemoData")) {
                       PrintWriter pw = givenResponse.getWriter();
                       pw.println("The answer is 42.");
                       pw.flush();
                       pw.close();
                 }
             }
         }
         catch (IOException ioe) {
         //MODIFY: log the io exception
         System.out.println("IOException occured." + ioe.getStackTrace());
         }
         //MODIFY: put your error message here
         return "data request could not be processed.";
        }
    }
    
  9. Remember to add that servlet mapping to your web.xml file. For security reasons, it is advisable to make such things only available through a named request dispatcher.

    Example 8-12 Servlet Mapping

    <servlet>
    <!-- should only be accessible through a named request dispatcher -->
    <!--  for ajax demo -->
    <servlet-name>MyDataService</servlet-name>
          <servlet-class>
               oracle.samples.wlp.jsf.portlets.ajaxdemo.MyDataService
          </servlet-class>
    </servlet>
    

Now you have the pieces in place to compile and restart your server so you can run AjaxEnabledPortlet just created. The portlet should display a link "Invoke Portlet Data API via Ajax" and a <div> that says "replace me".When the link "Invoke Portlet Data API via Ajax" is clicked, the "replace me" should be replaced by the data, "The answer is 42", coming back from the "MyDataService" servlet.This shows one way to invoke a data service using Ajax within a JSF portlet.

8.11 Understanding Navigation Within a JSF Portlet

This section discusses navigation between views within a JSF portlet:

8.11.1 Navigating Within a Portlet with the JSF Controller

This section discusses the use case in which a user interacts with a portlet, triggering an update to that portlet.

It is standard to use command buttons and command links tied to actions to control navigation through the JSF application. Example 8-13 uses a navigation rule and in Example 8-14 a commandButton uses that rule. With the JSF navigation controller, three different approaches may be used when defining the value for the action attribute on the command button or the command link:

  • The action attribute is not specified on the component. This indicates that the navigation is a postback to the same view.

  • The action attribute is a hard-coded name of a navigation path to follow. This name is mapped in the controller configuration in the faces-config.xml file linked to an actual view in Example 8-13.

  • The action attribute contains Expression Language (EL) that invokes a backing bean method to evaluate a navigation path or null to indicate postback.

Each of these approaches is valid when a JSF application is operating as a JSF portlet. The JSF portlet bridge ensures the URLs are written properly to maintain this behavior correctly within a portal.

Example 8-13 Navigation Configuration in faces-config.xml

<navigation-rule>
   <from-view-id>/portlets/sample/page2.jsp</from-view-id>
   <navigation-case>
      <from-outcome>gotoPage1</from-outcome>
      <to-view-id>/portlets/sample/page1.jsp</to-view-id>
   </navigation-case>
</navigation-rule>

Example 8-14 Command Button That Uses the Navigation Rule

<h:commandButton action="gotoPage1" id="gotoPage1Button"
                 value="Goto Page 1">
</h:commandButton>

8.11.2 Support for Redirects

The JSF navigation controller supports HTTP redirect as an annotation on a navigation case. The JSF controller issues an HTTP redirect to the client for the target page of the navigation case if it is configured to do so. Example 8-15 illustrates such a redirect navigation case. In Example 8-15, note the use of the explicit <redirect/> element to indicate a redirect. The navigation case does not work properly when the redirect configuration is used within a JSF portlet in WLP.

Example 8-15 Redirect in a Navigation Case

<navigation-rule>
   <from-view-id>/portlets/redirect/page2.jsp</from-view-id>
   <navigation-case>
      <from-outcome>gotoPage1</from-outcome>
      <to-view-id>/portlets/redirect/page1.jsp</to-view-id>
      <redirect/>
   </navigation-case>
</navigation-rule>

Depending on the context in which it is being called, the above redirect navigation case will either be ignored by the portal, or the rule will execute and send the user to the target page via an entire web page redirect, thus taking the user out of the portal context entirely. This behavior occurs because the redirect URL is not rewritten to remain within the portal environment. Therefore, you should avoid specifying redirect/ in the JSF navigation rules since it tries to redirect the entire web page and not just the portlet itself.

Another way to do a redirect to the same page is to use the Java portlet setEvent to redirect from a managed bean. For instance, after a user has successfully authenticated, the portlet should be redirected so the portal page is re-rendered with the authentication information. This can be done like this:

FacesContext fc = FacesContext.getCurrentInstance();
obj = fc.getExternalContext().getResponse();
ActionResponse ar = (ActionResponse) obj;
 ar.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal",
 "framework.redirectBeforeRender"),null);

This triggers a portal event to inform the container that it should refresh its components before rendering. In the authentication use case, this provides for the correct user experience by re-rendering the portal components to display any personalization effects for the authenticated user.

8.12 Interportlet Communication with JSF Portlets

The example described in this section assumes there are two JSF Java portlets set up in your portal. The example will explain how Interportlet Communication (IPC) can be set up between them, allowing one portlet (the sending portlet) to notify another portlet (the receiving portlet) of a user interaction. This is just a simple overview of one possible use case for using IPC in JSF -Java portlets; it is not a complete step-by-step example.

In this example, a user clicks a link in the sending portlet and as a result, the receiving portlet displays the URL tied to that link. So this example is about one portlet triggering a navigation event in another portlet. It may be helpful to brush up on the details of Interportlet Communication (IPC) with Java portlets, see Chapter 12, "Configuring Local Interportlet Communication." Note that events described in this section are Java Portlet Events and not the native WLP events.

In order to have a Java event handled by the Java Portlet and not automatically sent through to the JSR-329 bridge as a Faces event, the following <context-param> must be added to the web.xml file. This is documented in the JSR-329 spec, but noted here as well. In this snippet of XML as shown in Example 8-16, the javax.portlet.faces.autoDispatchEvents application parameter is set to false. This is a web application level setting, not a portlet-level setting.

Example 8-16 autoDispatchEvents Set to False

<!--  tells the bridge to let the jsr286 events process -->
<context-param>
    <param-name>javax.portlet.faces.autoDispatchEvents</param-name>
    <param-value>false</param-value>
</context-param>

This setting allows for Java portlets to have their annotated events called. Without it, all events are assumed to be JSF events and the portlet container is bypassed.

Receiving Portlet Setup

The Java portlet code for the portlet receiving the Java event is shown in Example 8-17. In this example, a subclass called ExampleIPCPortlet extends GenericFacesPortlet so that code can be added to handle the event and do customized processing in the doView() method. For more information about these methods, see Chapter 6, "Building Java Portlets."

Example 8-17 Java Portlet Example

public class ExampleIPCPortlet extends GenericFacesPortlet {
    private static String CURRENTVIEWID = "currentViewId";
    @Override
    protected void doView(RenderRequest request, RenderResponse response)
        throws PortletException, java.io.IOException
    {
        String view = (String) request.getParameter(CURRENTVIEWID);
        if (view != null) {
           request.setAttribute("javax.portlet.faces.viewId", view);
        }        super.doView(request, response);
     }
     @ProcessEvent(qname="{http://oracle.com/sampleEvents}display.change")
     public void processViewChange(EventRequest eRequest, EventResponse eResponse)
       throws PortletException, IOException
     {
        Event event = eRequest.getEvent();
        String eventValue = (String) event.getValue();
        // set the new view id
        eResponse.setRenderParameter(CURRENTVIEWID, eventValue);
    }
}

The portlet.xml (Example 8-18) file contains the definition of the event to be dispatched to the receiving portlet. The event is defined like this:

<event-definition>
     <qname xmlns:x="http://oracle.com/sampleEvents">x:display.change</qname>
     <value-type>java.lang.String</value-type>
</event-definition>

The portlet must be set up to listen for this event. The portlet.xml file snippet, shown in Example 8-18, contains an example of the receiving portlet definition. The <supported-processing-event> indicates the events to which the receiving portlet listens. Also note <portlet-class> for the receiving portlet is not GenericFacesPortlet, but the subclass name oracle.samples.wlp.jsf.portlets.ExampleIPCPortlet instead. The subclassing of GenericFacesPortlet was required to create a customized doView()method and the processViewChange()method shown above in the Example 8-17, "Java Portlet Example".

Example 8-18 portlet.xml

<portlet>
     <portlet-name>display</portlet-name>
     <display-name>display</display-name>
     <portlet-class>oracle.samples.wlp.jsf.portlets.ExampleIPCPortlet
     </portlet-class>
     <init-param>
         <name>javax.portlet.faces.defaultViewId.view</name>
         <value>/demo/display.jsp</value>
     </init-param>
     <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>view</portlet-mode>
     </supports>
     <portlet-info>
        <title>Display</title>
        <short-title>Display</short-title>
     </portlet-info>
     <supported-processing-event>
         <qname xmlns:x="http://oracle.com/sampleEvents">x:display.change</qname>
     </supported-processing-event>
</portlet>

When the link in the sending portlet is clicked, the display.change is fired and the receiving portlet (ExampleIPCPortlet) is set up to listen for that event. As a result, the receiving Java portlet sets a render parameter when processing the event. This render parameter is accessed when the doView() method is called, thus changing the receiving portlet's view when the portlet container completes the render request for the portlet.

Sending Portlet Setup

To create the sending portlet, which sends the event to the receiving portlet, a regular GenericFacesPortlet with a regular JSF-JSP file that uses a JSF managed bean to create a URL can be used. The .jsp file should contain a link that looks something like Example 8-19. In addition, the managed bean for this JSF view will contain the myURL method like shown in Example 8-20. This method sends an event with the URL it wants the portlet receiving the event to change its view to. (Hardcoding URLs like this example is not recommended in a production environment, but is here for demonstration purposes only.)

The Example 8-18 shows the XML necessary for the portlet to identify that it will send this Java portlet event. Note the <supported-publishing-event> added to its portlet definition.

<supported-publishing-event>
      <qname
       xmlns:x="http://oracle.com/sampleEvents"> x:display.change
      </qname>
</supported-publishing-event>

Example 8-19 .jsp File to Call a Bean

… //This is an example of a commandLink using a faces bean to create the action url //
 <t:commandLink action="#{ExampleBean.myURL}">
               <h:outputText value="my IPC example" />
 </t:commandLink>

Example 8-20 Faces Bean Method for "ExampleBean" That Sends the Event

public String myURL() {
   sendEvent("/demo/examples/myNext.jsp");
   return null;
}
public void sendEvent(String viewId){
       FacesContext fc = FacesContext.getCurrentInstance();
       Object obj = fc.getExternalContext().getResponse();
       if (obj instanceof ActionResponse){
          ActionResponse ar = (ActionResponse) obj;
          ar.setEvent
            (new QName("http://oracle.com/sampleEvents",
                       "display.change"),
                       viewId );
     }
}

To summarize the flow of events, when a user clicks the link in the sending portlet, the sending portlet uses the URL created at render time from myURL() in the bean code, which in turn calls sendEvent(viewId) with the appropriate URL. The sendEvent method then creates a Java portlet event which the receiving portlet is configured to listen, as shown above in the portlet.xml previously described. Upon receiving the event, the receiving portlet should display the "/demo/examples/myNext.jsp".

Now you have a portal example that uses JSF for its components and Java portlet eventing to trigger Interportlet Communication that invokes a navigational change of the listening portlet.

8.13 Namespacing

This section discusses namespacing issues that must be addressed when building JSF portlets. Namespacing often comes into play when multiple instances of the same portlet exist within the portal. When there is more than one instance of a portlet, or two different portlets are using similar Javascript, then each instance needs to label its component uniquely. This is commonly done with putting a unique instance Id in front of the portlet's components in order to uniquely identify them through code. The following sections describe ways to do this:

8.13.1 Client ID Namespacing with the View Components

When a JSF portlet is rendered onto a portal page, it can coexist with other JSF portlets on that same page. In JSF, like other web frameworks, it is critical that the Id attribute on each element of the X/HTML browser page is unique. JSF has the concept of a naming container, which provides an Id namespace to all components it contains. The most common naming container is the View component (the f:view tag).

Because all JSF portlets contain an f:view tag as the root component (otherwise, it's not really a JSF portlet but just a Java Portlet at that point), WebLogic Portal and the JSR-329 bridge, for most cases, can correctly introduce a namespace for all component Ids in each portlet.

8.13.2 Client ID Namespacing with the WLP NamingContainer

In the native JSF bridge, Oracle recommended the use of the NamingContainer component to strengthen the scoping mechanism within the portal. For JSF with Java Portlet technology, this practice is no longer necessary and causes problems if used. If migrating from the WLP native bridge to the JSR-329 bridge, remove any NamingContainer components from the JSF views.

8.13.3 Javascript Namespacing with Portlet Tag Library

There are scenarios when you may find it helpful to use the standard portlet tag library and the namespace tag, as shown in Example 8-21. The Java portlet specification mandates that this tag library be available in the portlet container to give .jsp files an access to the portlet-specific elements. In this example, the <div id …> is namespaced, so that each instance of this portlet contains a unique <div id …>, and allows code to access it accordingly by getting the instance label of the portlet. This is not unique to JSF portlets; a feature of the Java Portlet standard.

Example 8-21 Javascript Namespacing Example

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/portlet" prefix="portlet" %>

<portlet:namespace var="portletns"/>
.
.
.
<div id="<%=portletns%>_xprDiv" style="background-color: #ffcccc;">replace me
</div>
.
.
.

The WLP API also allows access to the portlet instance label for namespacing purposes via PortletPresentationContext and the PortletBackingContext. The method in JSFJavaPortletHelper Class called getInstanceLabel implements an example of one way to do this, and can be called from within a managed bean. The Ajax Enablement example shows how this can be used to change a <div> through an Ajax call.

8.14 Code Examples for Common Use Cases

These code examples are illustrated here for learning purposes. These examples describe one of the many ways to implement common use cases. Your business application may require an expansion to these concepts.

8.14.1 Uploading Images

This section discusses uploading a file and serving the uploaded file (or any resource) to the browser. JSF 1.1 and JSF 1.2 did not come with an equivalent JSF component tag for the HTML file upload tag of:

<input type="file" size="50" name="file" accept="image/png,image/jpeg,image/gif"/>

However, the third party tools such as Tomahawk provide such tags. In a JSR-286-based portlet, you can use multiple ways to upload files. One way is to create a pure JSR-286 solution, without using JSF because JSF does not provide the appropriate tag.

This section includes the following:

8.14.1.1 File Upload with HTML tags

If you are not interested in using a third party library, but want to do a file upload, then you need to create a normal HTML JSP and parse the form manually.

  1. Create the JSP file for uploading files. This should contain plain HTML elements since JSF 1.2 does not provide a similar component.

    Example 8-22 JSP File For Uploading Files Using Plain HTML Elements

    %@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
    <%@ page import="javax.portlet.*"%>
    <%@ taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
    <portlet:defineObjects />
    Example of multiple file upload.
    <form id="uploadForm" method="post" action="<portlet:actionURL/>"
    enctype="multipart/form-data">
    <table border="0">
    <tr>
        <td/>
    </tr>
    <tr>
       <td>Select your picture:</td>
       <td><input type="file" size="50" name="file"
    accept="image/png,image/jpeg,image/gif" /></td>
    </tr>
    <tr>
       <td/>
    </tr>
    <tr>
        <td>Select your picture:</td>
        <td><input type="file" size="50" name="file"
    accept="image/png,image/jpeg,image/gif" /></td>
    </tr>
    <tr>
        <td><input type="submit" value="Upload" /></td>
    </tr>
    </table>
    </form>
    <%
        String message = renderRequest.getParameter("renderMessage");
        if (message != null) {
      %>
    <pre>
    <%= message %>
    </pre>
    <%
      }
    %>
    
  2. Create the Java class to parse your form. Example 8-23 uses the javax.mail.* classes to process the content from the multipart form. It uses a class called FormDataHelper. This class takes an ActionRequest from the processAction JSR-286 method.

    Example 8-23 FormDataHelper

    package oracle.samples.wlp;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.activation.DataSource;
    import javax.mail.BodyPart;
    import javax.mail.MessagingException;
    import javax.mail.internet.MimeBodyPart;
    import javax.mail.internet.MimeMultipart;
    import javax.portlet.ActionRequest;
    import javax.portlet.PortletException;
    
    /**
     * This uses the javax.mail classes to take the content from the multipart form.
     * This is called from the 'processAction' method of a JSR286 portlet.
     * To construct this class, send in the actionRequest from the processAction
       method.
     *
     */
    public class FormDataHelper {
      // The MIME prefix for all multipart media types
      private static final String MULTIPART_PREFIX = "multipart/";
      // The MIME content type for the file upload form data
      private static final String MULTIPART_FORM_DATA = "multipart/form-data";
      // The MIME content type for plain text data
      private static final String PLAIN_TEXT = "text/plain";
      private ActionRequest actionRequest;
      //these are initialized lazily
      private Map<String, List<String>> formParams;
      private Map<String, List<MimeBodyPart>> formBodyParts;
      private boolean mIsInitialized=false;
      private boolean mHasMultipart=false;
      /**
        * Constructor
        */
      public FormDataHelper(ActionRequest request)
      {
      actionRequest = request;
      }
      /**
        * Get the parameter value for the given name
        * @param name
        * @return
        * @throws PortletException
        */
      public String getParameter(String name)
        throws PortletException
      {
         String value = actionRequest.getParameter(name);
         if (value != null){
            return value;
     }
    // If we don't find a value, make sure we have parsed in the parameters and body parts
         initParameters();
         if (!mHasMultipart)
         {
           return null;
         }
         List<String> paramList = (List<String>)formParams.get(name);
         if (paramList != null)
         {
         return (String)paramList.get(0);
         }
        else
        {
           return null;
        }
    }
    /**
     * Get all the parameter values for the given name
     * @param name
     * @return
     * @throws PortletException
     */
    public String[] getParameterValues(String name)
    throws PortletException
    {
       String[] values = actionRequest.getParameterValues(name);
       if (!mHasMultipart)
       {
          return values;
       }
       // Make sure we have parsed in the parameters and body parts
       initParameters();
         List<String> valueList = formParams.get(name);
         if (valueList == null)
         {
            return values;
         }
            else
         {
             int size = valueList.size();
             if (values != null)
             {
                List<String> newValueList = new ArrayList<String>(values.length +
                size);
                newValueList.addAll(Arrays.asList(values));
                newValueList.addAll(valueList);
                valueList = newValueList;
            }
            values = new String[size];
            valueList.toArray(values);
            return values;
       }
    }
    /**
     * Get mime body part
     * @param name
     * @return
     * @throws PortletException
     */
    public MimeBodyPart getMimeBodyPart(String name)
    throws PortletException
    {
        // Make sure we have parsed in the parameters and body parts
        initParameters();
        if (!mHasMultipart)
        {
          return null;
        }
        List<MimeBodyPart> parts = (List<MimeBodyPart>)formBodyParts.get(name);
        return parts == null ? null : (MimeBodyPart)parts.get(0);
    }
    /**
     * Get all the mime parts for the given name
     * @param name
     * @return
     * @throws PortletException
     */
    public MimeBodyPart[] getMimeBodyParts(String name)
    throws PortletException
    {
    // Make sure we have parsed in the parameters and body parts
      initParameters();
      if (!mHasMultipart)
      {
        return null;
      }
      List<MimeBodyPart> parts = formBodyParts.get(name);
      if (parts == null)
      {
        return null;
      }
      MimeBodyPart[] mimeBodyParts = new MimeBodyPart[parts.size()];
    parts.toArray(mimeBodyParts);
    return mimeBodyParts;
    }
    /*
     * Lazy initialization of the parameter map and body parts.
     * This is what processes the form and figures out what is there.
     */
    private void initParameters() throws PortletException
    {
      if (mIsInitialized)
    {
      return;
    }
    // Strip off any extra attributes and whitespace from the content type,
    // so we can compare it
      String contentType = actionRequest.getContentType();
      if (contentType == null)
    {
      mIsInitialized = true;
      return;
    }
      int sepIndex = contentType.indexOf(';');
      if (sepIndex != -1)
    {
        contentType = contentType.substring(0, sepIndex).trim();
    }
       if (contentType.equalsIgnoreCase(MULTIPART_FORM_DATA))
     {
         formParams = new HashMap<String, List<String>>(20);
         formBodyParts = new HashMap<String, List<MimeBodyPart>>(20);
         DataSource datasource = new DataSource()
             {
                 public InputStream getInputStream() throws IOException
                 {
                     return actionRequest.getPortletInputStream();
                 }
                 public OutputStream getOutputStream() throws IOException
                 {
                     throw new IOException("OutputStream not available");
                 }
                 public String getContentType()
                 {
                     return actionRequest.getContentType();
                 }
                 public String getName()
                 {
                     return getClass().getName();
                 }
             };
         try
         {
             MimeMultipart multipartMessage = new MimeMultipart(datasource);
             parseMultiPart(multipartMessage, null);
         }
         catch (MessagingException me)
         {
             throw new PortletException(me);
         }
         catch (IOException ioe)
         {
             throw new PortletException(ioe);
         }
         mHasMultipart = true;
      }
     mIsInitialized = true;
    }
    private void parseMultiPart(MimeMultipart multipartMessage, String parentFieldName)
    throws MessagingException, IOException
    {
      int partCount = multipartMessage.getCount();
      // Go through each body part, decided on its 'type' and add to the
      // parameter map and file list as appropriate
      BodyPart part;
      MimeBodyPart mimePart;
      Object content;
      String[] disps;
      String disp, lcDisp;
      List<MimeBodyPart> partValues;
      List<String> values;
      for (int i = 0; i < partCount; i++)
    {
      part = multipartMessage.getBodyPart(i);
      if (!(part instanceof MimeBodyPart))
    {
      continue;
    }
      mimePart = (MimeBodyPart)part;
      // The Content Disposition header tells us how to treat the body part
      disps = mimePart.getHeader("Content-Disposition");
      if (disps == null || disps.length == 0)
    {
      continue;
    }
      disp = disps[0];
      lcDisp = disp.toLowerCase();
      // Get the field name out of the disposition header, if present
      int nameStart, nameEnd;
      if ((nameStart = lcDisp.indexOf("name=\"")) != -1 &&
      (nameEnd = lcDisp.indexOf("\"", nameStart + 6)) != -1)
    {
       parentFieldName = disp.substring(nameStart + 6, nameEnd);
    }
      // If we don't have a field name, there's not much we can do with this body part
      if (parentFieldName == null)
    {
      continue;
    }
      // If this is a multipart body part, we recurse on its contents using
      // the current field name
      if (mimePart.getContentType().toLowerCase().startsWith(MULTIPART_PREFIX))
    {
      content = mimePart.getContent();
      if (content instanceof MimeMultipart)
        {
           parseMultiPart((MimeMultipart)content, parentFieldName);
        }
    }
    // Decide whether this is a parameter or a file, according to whether
    // the filename attribute is present in the disposition header
    else if ((nameStart = lcDisp.indexOf("filename=\"")) != -1 &&
    (nameEnd = lcDisp.indexOf("\"", nameStart + 10)) != -1)
    {
      partValues = formBodyParts.get(parentFieldName);
      if (partValues == null)
       {
        partValues = new ArrayList<MimeBodyPart>();
        formBodyParts.put(parentFieldName, partValues);
    }
    partValues.add(mimePart);
    //get the Filename from header -- so we can clip the path if it exists.
     String
     filename=getFileNameFromHeader(lcDisp.substring(nameStart+10,lcDisp.length()-1));
       if (!(filename).equals(mimePart.getFileName())){
       mimePart.setFileName(filename);
      }
    }
       else if (mimePart.getContentType().toLowerCase().startsWith(PLAIN_TEXT))
    {
      content = mimePart.getContent();
      if (content instanceof String)
       {
       values = formParams.get(parentFieldName);
       if (values == null)
               {
                 values = new ArrayList<String>();
                 formParams.put(parentFieldName, values);
               }
         values.add((String)content);
           }
        }
      } // end for each body part
    }
    private String getFileNameFromHeader(String filename){
    // The filename may contain a full path.  Cut to just the filename.
       int slash =
        Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
        if (slash > -1) {
        filename = filename.substring(slash + 1);  // past last slash
          }
         return filename;
       }
    }
    
  3. Create the Java portlet class that extends GenericJavaPortlet, as shown in Example 8-24. Use this class when generating your Java Portlet (.portlet file) through the IDE. Notice that the processAction method instantiates the FormDataHelper class and processes the file data out of the mime parts.

    Example 8-24 JavaFileUploadPortlet

    package oracle.samples.wlp.portlets;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import javax.faces.application.FacesMessage;
    import javax.faces.context.FacesContext;
    import javax.mail.MessagingException;
    import javax.mail.internet.MimeBodyPart;
    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.GenericPortlet;
    import javax.portlet.PortletException;
    import javax.portlet.PortletRequestDispatcher;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    import oracle.samples.wlp.FormDataHelper;
    /**
     * A JSR286 portlet that uploads content from a multipart form.
     * This was intended to use with JSF for the form,
     * but JSF does not have a component equivalent to the <input type="file" />,
     * so instead it uses a .jsp file for the html for this portlet.
     */
    public class JavaFileUploadPortlet extends GenericPortlet {
    private static final String DISPATCH_JSP = "/demo/fileupload/fileupload.jsp";
    /**
     * Dispatches to a jsp to display the form.
     */
    public void doView(RenderRequest renderRequest, RenderResponse renderResponse)
        throws PortletException, IOException
        {
      PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher(DISPATCH_JSP);
     rd.include(renderRequest, renderResponse);
    }
    /**
     * Takes the action request which creates a FormDataHelper so that the multipart
     * form data can be accessed.
     */
    @Override
    public void processAction(ActionRequest actionRequest, ActionResponse actionResponse)
    {
            FormDataHelper formdata = new FormDataHelper(actionRequest);
            try {
            MimeBodyPart[] mimeparts = formdata.getMimeBodyParts("file");
            int uploaded =0;
            if (mimeparts == null)
            {
            actionResponse.setRenderParameter("renderMessage", "Didn't find files to upload.");
            return;
            }
            for (MimeBodyPart filedata: mimeparts){
            // Just to demonstrate what information you can get from the uploaded file.
            System.out.println("File type: " + filedata.getContentType());
            System.out.println("File name: " + filedata.getFileName());
            System.out.println("File size: " + filedata.getSize() + " bytes");
            
            /************  your business logic here  ************
             * This is writing the image to the "uploadedcontent"
     * directory under WebContent.
             * This directory needs read/write permissions by the 'user
     * running the webserver'.
             */
            InputStream inputstream = filedata.getInputStream();
            if (filedata.getSize() > 0){
            byte [] imageBytes = new byte[inputstream.available()];
            inputstream.read(imageBytes);
            String realpath = getPortletContext().getRealPath("/uploadedcontent/");
            File file =new File(realpath + "/" + filedata.getFileName());
            FileOutputStream fop=new FileOutputStream(file);
            fop.write(imageBytes);
            fop.flush();
            fop.close();
            uploaded++;
                }
            }
            actionResponse.setRenderParameter("renderMessage", "Uploaded " + uploaded + " files.");
           }
            catch (PortletException e) {
            // Show error message.
                FacesContext.getCurrentInstance().addMessage("uploadForm", new FacesMessage(
                    FacesMessage.SEVERITY_ERROR, "File upload failed with PortletException error.", null));
    e.printStackTrace();
            }
    catch (MessagingException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    } 
    catch (IOException e) {
    FacesContext.getCurrentInstance().addMessage("uploadForm", new FacesMessage(
                    FacesMessage.SEVERITY_ERROR, "File upload failed with IOException error.", null));
    e.printStackTrace();
    }
            
        }
    }
    

From here, you could expand your HTML to create a separate portlet to display the content you just uploaded. This is just an example of how to upload content. Typically, the location of the uploaded content is configurable.

8.14.1.2 File Upload with Tomahawk tags

To avoid writing your own parsing mechanism, another option is to install third party libraries like Tomahawk. Tomahawk provides the component called inputFileUpload that provides the capability to upload content. Although WebLogic Portal does not explicitly support it, you can use this component by adding third party libraries. See Third-Party Libraries for more details on how to configure this library.

8.14.2 Login/Logout Example

Another common example that nearly every web application needs is the capability to authenticate/unauthenticate the user. This section provides some code examples to help you develop login/logout functionality within Java-JSF portlets. There are multiple ways to develop this functionality, this section focuses on some of them.

This section includes the following:

8.14.2.1 Login Portlet Design

The login portlet discussed in this section is implemented in JSF. It uses a single view that toggles the visibility of the login/logout controls based on the authenticated state of the user.

This login portlet offers the following features:

  • Implemented as a JSF portlet

  • A single view with two forms - one for login and one for logout

  • Uses a JSF managed bean and dispatches to a servlet to perform the authentication logic

  • Employs the JSF localization facility

This is different from a typical web application since in a web application the login/logout page is normally the first screen the user reaches and thus all future pages have an authenticated session. In the portal paradigm, the user may access portlets within a portal without logging in and seeing a non-customized view of the application. Then, once he/she does login, via a login portlet like shown here, then all other portlets within the portal must re-render with this new authenticated session and show the user's customized view. The opposite is true once a user logs out. This need to re-render all the components in the portal tree adds a little more complexity to managing login/logout functionality in a portal vs a regular web application.The two biggest considerations for the developer are triggering redirects to manage the re-rendering of the component tree, and authenticating/unauthenticating the user session within the middle of a JSF lifecycle.

8.14.2.2 Handling Redirects with JSR-286/JSR-329

By the time a user is authenticated, the portal framework has also started processing the rendered page. It is too late for the framework to re-compute the page. Therefore, the solution is to force a redirect after the user logs in or logs out via the login portlet. In the native bridge architecture, this is accomplished via a backing file. But with JSR-286/JSR-329, this can be simplified because JSR-329 allows for backing bean action methods to trigger events to do redirects.

8.14.2.3 Invalidating the Session with the JSR-329 Bridge

The WLP JSF portlet native bridge's limitation is that a user's HttpSession cannot be invalidated when the JSF lifecycles are processing. This is no longer an issue with the JSR-329 bridge.

8.14.3 Login Portlet Implementation

This section includes the following:

8.14.3.1 JSF Login View

The login.jsp page contains two forms - one for login and one with a button to logout. Only one form is visible at a time, and the visibility is controlled by a flag that indicates whether the user is authenticated.

Example 8-25 The login.jsp for the JSF 1.2 Login Portlet

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%>
<f:view>
    <f:loadBundle basename="oracle.samples.wlp.jsf.portlets.login.loginportlet"  var="i18n" />
      <h:form id="loginBeanForm"   rendered="#{!JSFLoginPortletRequestBean.authenticated}">
      <h:panelGrid id="outerLayout" columns="1" width="100%" style="background-color: azure;">
      <h:panelGroup id="titleLine">
      <h:outputText value="#{i18n.login_intro}:" style="color: cornflowerblue; font-size: medium"/>
   </h:panelGroup>
        <h:messages  layout="table" showDetail="false" showSummary="true" style="color: red;" />
   <h:panelGroup id="formFields">
   <h:panelGrid columns="2" width="60%"
      style="background-color: azure">
   <h:panelGroup style="text-align: right">
   <h:outputText value="#{i18n.login_username}:"/>
   </h:panelGroup>
      <h:panelGroup style="text-align: left">
      <h:inputText id="username" required="true"
   value="#{JSFLoginPortletRequestBean.username}" />
   </h:panelGroup>
      <h:panelGroup style="text-align: right">
      <h:outputText value="#{i18n.login_password}:"/>
   </h:panelGroup>
      <h:panelGroup style="text-align: left">
      <h:inputSecret id="password" required="true"
      value="#{JSFLoginPortletRequestBean.password}" />
  </h:panelGroup>
   <h:panelGroup/>
   <h:panelGroup style="text-align: left">
   <h:commandButton id="loginButton" immediate="false" action="#{JSFLoginPortletRequestBean.authenticate_generic}" value="#{i18n.login_button}"/>
    </h:panelGroup>
    </h:panelGrid>
    </h:panelGroup>
   </h:panelGrid>
</h:form>
   <h:form id="logoutForm" rendered="#{JSFLoginPortletRequestBean.authenticated}">
   <h:panelGrid id="outerLayout" columns="1" width="100%" style="background-color: azure;">
   <h:commandButton action="#{JSFLoginPortletRequestBean.userLogout_generic}"  id="logoutButton" value="#{i18n.logout_button}"/>
   </h:panelGrid>
</h:form>
</f:view>

8.14.3.2 JSF Managed Backing Bean

The login.jsp in Example 8-25 uses a JSF managed bean, which is shown in Example 8-26. Notice the JSF managed backing bean calls the JSFJavaPortletHelper class which contains the core logic to log the user in.

Example 8-26 JSF Managed Bean Calls the JSFJavaPortletHelper Class

package oracle.samples.wlp.jsf.portlets.login;
import java.io.Serializable;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import oracle.samples.wlp.jsf.JSFJavaPortletHelper;
public class JSFLoginPortletRequestBean implements Serializable {
private static final long serialVersionUID = 1L;
private static final String BUNDLE_NAME =
"oracle.samples.wlp.jsf.portlets.login.loginportlet";
private String username;
private String password;
private String action;
// ACTION METHODS
/**
     * Action method for the login CommandButton
     * Uses non-wlp specific way of authentication
     *
     * @return
     */
    public String authenticate_generic() {
        // perform the actual authentication call
        setAction("login");
        boolean success = JSFJavaPortletHelper.authenticate_generic(username, password);
        if (success) {
            // Wipe out the given username & password, just in case someone
            // is tempted to make this bean Session scoped (should be
            // Request) By keeping this password around in the bean,
            // it is open to temptation for abuse
            password = "invalidated";
            username = "invalidated";
        }
        else {
            //Login Failed
            String errorText = JSFJavaPortletHelper.getBundleMessage(BUNDLE_NAME, "login_error");
            // Add the message to the context
            FacesContext fc = FacesContext.getCurrentInstance(); 
            FacesMessage msg = new FacesMessage(
                  FacesMessage.SEVERITY_ERROR, errorText, errorText);
            fc.addMessage(null, msg);
            
        }
        return null;
    }
    /**
     * Action method called during logout for the servlet to do the logout
     */
    public String userLogout_generic() {
        setAction("logout");
        JSFJavaPortletHelper.logout_generic();
        return null;
    }
// GETTERS AND SETTERS*** @return true if the user is authenticated*/public boolean isAuthenticated() {
    return JSFJavaPortletHelper.isAuthenticated();
}
/**
* @return the user name
*/
public String getUsername() {
    return this.username;
}
public String getUsernameForDisplay(){
    return JSFJavaPortletHelper.getUsernameForDisplay("");
    }
/**
* @param username the user name to be authenticated
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Retrieves a placeholder for the password. We never
* want to display back the actual password to the user,
* so just return an empty string
* @return an empty String
*/
public String getPassword() {
  return this.password;
}
/**
* @param password the password to be used for authentication
*/
public void setPassword(String password) {
this.password = password;
}
public String getAction() {
   return this.action;
}
public void setAction(String action) {
   this.action = action;
}
}

The managed bean needs to be wired into the application. XML element shown in Example 8-27 must be added to faces-config.xml.

Example 8-27 Registering the Login Managed Bean in faces-config.xml

<managed-bean>
   <description>Handles authentication for the Login portlet.</description>
   <managed-bean-name>JSFLoginPortletRequestBean</managed-bean-name>
    <managed-bean-class>
       oracle.samples.wlp.jsf.JSFLoginPortletRequestBean
   </managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>

8.14.3.3 Resource Bundle

A good practice is to create a resource bundle for the portlet. This should be located in a file that matches the basename of the <f:loadBundle> tag. In this example the resource bundle is in: oracle/samples/wlp/jsf/portlets/login/loginportlet.properties in the Java resources /src folder.

Example 8-28 Login.jsp

#login.jsp
login_titlle=Login Page
login_imageAlt=Login
login_intro=Please enter your username and password 
login_username=Username
login_password=Password
login_button=Login 
logout_button=Logout
login_error=The username or password are invalid.
welcome_intro=Welcome

8.14.3.4 Portlet Definition File

Example 8-29 contains the pieces that tie together all the pieces described in this section. The .portlet file defines the portlet name and that it is a Java portlet.

Example 8-29 The Portlet Definition File for the Login Portlet (JSF 1.2 Java Portlet)

<?xml version="1.0" encoding="UTF-8"?>
<portal:root
    xmlns:netuix="http://www.bea.com/servers/netuix/xsd/controls/netuix/1.0.0"
    xmlns:portal="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0 portal-support-1_0_0.xsd">
    <netuix:javaPortlet
        definitionLabel="login_generic" portletName="DemoLoginGeneric" title="Generic Login"/>
</portal:root>

Example 8-30 portlet.xml File

<portlet>
     <portlet-name>DemoLoginGeneric</portlet-name>
     <display-name>DemoLoginGeneric</display-name>
     <portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
     <init-param>
         <name>javax.portlet.faces.defaultViewId.view</name>
         <value>/demo/generic/login.jsp</value>
     </init-param>
     <supports>
        <mime-type>text/html</mime-type>
        <portlet-mode>view</portlet-mode>
     </supports>
     <portlet-info>
        <title>Login</title>
        <short-title>Login</short-title>
     </portlet-info>
</portlet>

The portlet.xml file in Example 8-30 shows that the DemoLogin portlet from the .portlet XML file is a GenericFacesPortlet, and contains defaultViewId.view as an init-param. If you subclassed GenericFacesPortlet, the subclass name should be in the <portlet-class> element. The <init-param> element of javax.portlet.faces.defaultViewId.view points to the login.jsp shown in Example 8-28. When the developer is creating a portlet via the portlet editor in workshop, and saves the portlet, then the .portlet file gets created as does the entry in the portlet.xml file. This is how the pieces are tied together.

Let's review the pieces we have and how they work together. The browser requests to view this portlet, the portlet container determines that it is a Java portlet, so it looks in the portlet.xml file for the class name, the class is instantiated and calls the login.jsp because that is what the defaultViewId is set to. Now the login.jsp uses the managed bean. This managed bean is invoked when a user submits the form. The web container recognizes the managed bean since it is configured in the faces-config.xml file.

Notice that the managed bean uses a class called JSFJavaPortletHelper (JSFJavaPortletHelper Class). In this code, you will notice that the actual authentication happens in a servlet named LoginServlet.

In the servlet, there are some important things to note. First, the HttpServletRequest that the LoginServlet receives from the dispatch is a wrapped HttpServletRequest. The WLS ServletAuthentication class requires a non-wrapped request in its method calls. So, the unwrap method in this LoginServlet example displays how the given wrapped HttpServletRequest can be unwrapped to get the actual HttpServletRequest the ServletAuthentication methods require.

Second, after authenticating, an attribute is associated with the request so the managed bean can use it to determine if the login/logout was successful. This is a design decision at this point, and you may have other security checks to do before a user can log in. Moreover, you should namespace this attribute name carefully in real-world implementations.

Example 8-31 LoginServlet

package oracle.samples.wlp.jsf.portlets.login;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import oracle.samples.wlp.jsf.portlets.login.JSFLoginPortletRequestBean;
import weblogic.servlet.security.ServletAuthentication;
/**
 * Login servlet that authenticates/unathenticates the user.
 *
 */
public class LoginServlet extends HttpServlet {
    public static final String AUTHENTICATED="LoginServlet.authenticated";
    public void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
        doLoginLogout(request,response);
    }
        public void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    
        doLoginLogout(request,response);
    }
    /**
     * Login in the user. 
     * Instead of using ServletAuthentication, use your company's login logic in this servlet.
     * 
     * The request is updated with an attribute of "authenticated" with a boolean value of 
     * true = user is authenticated, false = the user is NOT authenticated;
     * 
     * Note:  The given request needs to be unwrapped, so that Weblogic Server gets an unwrapped request in order
     * to do authentication.  The given request needs to be kept, so that an attribute can be added to it and be
     * seen on the JSFLoginPortletRequestBean.
     * 
     * @param request
     * @param response
     */
    public void doLoginLogout(HttpServletRequest givenRequest, HttpServletResponse givenResponse){
                JSFLoginPortletRequestBean loginPortletRequestBean = (JSFLoginPortletRequestBean)
givenRequest.getAttribute("JSFLoginPortletRequestBean");
        if (loginPortletRequestBean != null) {
            if (loginPortletRequestBean.getAction().equals("login")) {
                //Note:  wls specific authentication here.  Implement your own here as necessary.
                HttpServletRequest unwrappedRequest = unwrap(givenRequest);
                int result =
ServletAuthentication.weak(loginPortletRequestBean.getUsername(),
loginPortletRequestBean.getPassword(),unwrappedRequest,givenResponse);
                givenRequest.setAttribute(AUTHENTICATED, result == ServletAuthentication.AUTHENTICATED);
            }
            else {
                if (loginPortletRequestBean.getAction().equals("logout")) {
                    givenRequest.getSession().invalidate();
                    givenRequest.setAttribute(AUTHENTICATED, false);
                }
            }
        }
    }
    /**
     * Need to unwrap the request, so we can send the real request to the ServletAuthentication
     * @param request
     * @return HttpServletRequest
     */
    private HttpServletRequest unwrap(HttpServletRequest request){
        while (request instanceof HttpServletRequestWrapper) {
            HttpServletRequestWrapper wrequest = (HttpServletRequestWrapper) request;
            request =(HttpServletRequest) wrequest.getRequest();
        }
        return request;
    }
}

Remember you must add your servlet class to the web.xml file.

<servlet>
<!-- should only be accessible thru a named request dispatcher -->
<servlet-name>LoginServlet</servlet-name>
<servlet-class>oracle.samples.wlp.jsf.portlets.login.LoginServlet</servlet-class>
</servlet>

8.14.3.5 Redirect

The next important topic is redirect. Notice that both the authenticate() and logout() methods do a redirect. The page must be redirected so that any other portlets on the portal re-retrieve their markup to the newly authenticated/unauthenticated user. There are other ways of doing a redirect, but in WLP, this is the recommended way, which is called send an event. The code snippet is:

//redirect the page, so any customization for this user is picked up after successful login
      obj = fc.getExternalContext().getResponse();
      ActionResponse ar = (ActionResponse) obj;
      r.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal", "framework.redirectBeforeRender"),null);

8.14.4 Putting Login Portlet Into A Portal environment

The login portlet is ready, now let's see it working in a portal environment. To do this, you need to create a second portlet, called WelcomePortlet in this example. It will change the display to show the user name once login has occurred and no name once logout has occurred. The expected behavior is to see the WelcomePortlet refresh to show the authenticated user's version.

Example 8-32 shows the welcome.portlet file.

Example 8-32 welcome.portlet File

<?xml version="1.0" encoding="UTF-8"?>
<portal:root
   xmlns:netuix="http://www.bea.com/servers/netuix/xsd/controls/netuix/1.0.0"
   xmlns:portal="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xsi:schemaLocation="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0
   portal-support-1_0_0.xsd">
    <netuix:javaPortlet        
       definitionLabel="welcome" portletName="welcome" title="Welcome"/>
</portal:root>

Example 8-33 Entry in the portlet.xml file

<portlet>
    <portlet-name>welcome</portlet-name>    
    <display-name>welcome</display-name>
<portlet-class>javax.portlet.faces.GenericFacesPortlet</portlet-class>
   <init-param>        
       <name>javax.portlet.faces.defaultViewId.view</name>
       <value>/demo/welcome.jsp</value>    
   </init-param>    
 <supports>
      <mime-type>text/html</mime-type>
      <portlet-mode>view</portlet-mode>    
  </supports>    
  <portlet-info>        
    <title>Welcome</title>        
    <short-title>Welcome</short-title>    
  </portlet-info>      
</portlet>

Notice that the defaultViewId is the welcome.jsp. The welcome.jsp then uses the JSFLoginPortletRequestBean to determine if authentication has occurred and to show the user's display name.

Example 8-34 welcome.jsp

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="f"  uri="http://java.sun.com/jsf/core"%>
<%@ taglib prefix="h"  uri="http://java.sun.com/jsf/html"%>
<f:view>
    <f:loadBundle basename="oracle.samples.wlp.jsf.portlets.login.loginportlet" var="i18n" />
<h:form id="welcomeGenericForm" rendered="#{!JSFLoginPortletRequestBean.authenticated}">
        <h:outputText value="#{i18n.welcome_intro}" />
    </h:form>
<h:form id="welcomeUserForm" rendered="#{JSFLoginPortletRequestBean.authenticated}">
        <h:outputText value="#{i18n.welcome_intro}" />
<h:outputText  value="#{JSFLoginPortletRequestBean.usernameForDisplay}"/>
    </h:form>
</f:view>

Now add the WelcomePortlet to a portal using the workshop IDE. The resulting .portal file should look something like Example 8-35.

Example 8-35 demo.portal

<?xml version="1.0" encoding="UTF-8"?>
<portal:root xmlns:html="http://www.w3.org/1999/xhtml-netuix-modified/1.0.0"
    xmlns:netuix="http://www.bea.com/servers/netuix/xsd/controls/netuix/1.0.0"
    xmlns:portal="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.bea.com/servers/netuix/xsd/portal/support/1.0.0
portal-support-1_0_0.xsd">
    <netuix:desktop definitionLabel="demo_demo_portal" discEnabled="false"
dvtEnabled="false"
        encoding="UTF-8" markupName="desktop" markupType="Desktop"
scrollToWindow="true"
        title="New Portal Desktop" treeOptimizationEnabled="true">
        <netuix:lookAndFeel definitionLabel="bighornLookAndFeel"
            description="A look and feel using the bighorn skin and skeleton"
            markupName="bighornLookAndFeel" markupType="LookAndFeel"
skeleton="bighorn"
            skin="bighorn" title="Bighorn">
            <netuix:titlebarButtonOrder>
                <netuix:otherButtons/>
                <netuix:namedButton name="float"/>
                <netuix:namedButton name="edit"/>
                <netuix:namedButton name="help"/>
                <netuix:namedButton name="minimized"/>
                <netuix:namedButton name="maximized"/>
                <netuix:namedButton name="delete"/>
            </netuix:titlebarButtonOrder>
        </netuix:lookAndFeel>
        <netuix:shell description="A header and footer is included in this shell."
            markupName="headerFooter" markupType="Shell" title="Header-Footer
Shell">
            <netuix:head/>
            <netuix:body>
                <netuix:header/>
                <netuix:book defaultPage="demo_demo_portal_page_1"
                    definitionLabel="demo_demo_portal_book_1" markupName="book"
                    markupType="Book" title="Main Page Book">
                    <netuix:singleLevelMenu
                        description="This menu provides a single level of tabs
used to navigate across pages."
                        markupName="singleLevelMenu" markupType="Menu"
                        title="Single Level Menu"/>
                    <netuix:content>
                        <netuix:page definitionLabel="demo_demo_portal_page_1"
                          markupName="page"
                            markupType="Page" title="Main">
                            <netuix:content>
                                <netuix:flowLayout
                                    description="This layout uses the flowLayout
                                    control to create two columns in which
                                    placeables flow vertically."
                                                         htmlLayoutUri="/framework/markup/layout/twocolumn.html.txt"
                                       iconUri="/framework/markup/layout/twocolumn.gif"
                                    markupName="twoColumnFlowLayout"
                                    markupType="Layout"
                                    orientation="horizontal" title="Two Column
                                    Flow Layout">
                                    <netuix:placeholder
                                        description="The left most placeholder in
                                        this layout."
                                        markupName="twoColumnFlow_left"
                                        markupType="Placeholder"
                                        title="left" usingFlow="false"
                                        width="25%">
                                        <netuix:portletInstance
                                         contentUri="/demo/login.portlet"
                                         instanceLabel="login_1"
                                          markupType="Portlet" title="Login"/>
                                    </netuix:placeholder>
                                    <netuix:placeholder
                                        description="The right most placeholder in
                                        this layout."
                                        markupName="twoColumnFlow_right"
                                        markupType="Placeholder"
                                        title="right" usingFlow="false"
                                        width="65%">
                                        <netuix:portletInstance
                                            contentUri="/demo/welcome.portlet"
                                            instanceLabel="welcome_1"
                                            markupType="Portlet" title="Welcome"/>
                                    </netuix:placeholder>
                                </netuix:flowLayout>
                            </netuix:content>
                        </netuix:page>
                    </netuix:content>
                </netuix:book>
                <netuix:footer/>
            </netuix:body>
        </netuix:shell>
    </netuix:desktop>
</portal:root>

Now when running the portal, the first time rendered, the user isn't authenticated.

Figure 8-4 First Time/ Not Authenticated

Description of Figure 8-4 follows
Description of "Figure 8-4 First Time/ Not Authenticated"

Then, after logging in, it should look like Figure 8-5.

The redirect should automatically happen, which causes the WelcomePortlet to refresh itself and welcomes the new user.

8.15 Preparing JSF Portlets for Production

This section discusses best practices to follow before deploying a JSF portlet into a production environment.

8.15.1 Configuration Tasks

This section discusses configuration tasks to perform before deploying a JSF portlet to a production environment.

8.15.1.1 Configuring URL Templates for Proxy Servers

WLP is responsible for generating URLs that properly stay within the context of the portal. WLP does this for page tabs and also for portlet links. Section 8.11, "Understanding Navigation Within a JSF Portlet" describes how WLP rewrites links for JSF Command Button and Link components automatically.

In production, the URL that a user enters to navigate to a WebLogic Portal instance must not target the machine hosting that instance. The user should instead be routed through a proxy server or load balancer. This is a best practice for scalability and security. WLP provides a configuration feature for configuring URLs properly in such an environment. The JSF link rewriting mechanism honors this non-JSF configuration feature.

For more information on the WLP URL template feature, see the section "Working with URLs" in the Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal. Even though Apache Beehive dependency has been removed as of the 10.3.2 release, the following template configuration is still valid for proxy server configuration. You do not need the Apache Beehive facet for this configuration file to work.

The steps for configuring URLs to make use of a proxy server are:

  1. In Eclipse, in your Portal Web Project, go to the Merged Resources view.

  2. Right-click WEB-INF/beehive-url-template-config.xml, then choose Copy to Project.

  3. Go to the Project Navigation view, then double-click the copied file.

  4. Add the URL template entry shown in Example 8-36, replacing the IP address with the IP address of the proxy server or load balancer.

  5. Configure the proxy server to forward to WebLogic Portal. (See your vendor's proxy server configuration documentation for instructions on how to do this.)

    Example 8-36 Configure URL Generation That Refers to a Proxy Server

    <url-template>
        <name>default</name>
        <value>http://192.168.0.5:{url:port}/{url:path}?{url:queryString}     {url:currentPage}
        </value>
    </url-template>
    

8.15.1.2 JSF Portlets with WSRP

When developing portlets with JSF, the WSRP capabilities of WLP work correctly. JSF portlets can be exposed as WSRP portlets, just as with any other portlet type. For detailed information on WSRP portlets, see Oracle Fusion Middleware Federated Portals Guide for Oracle WebLogic Portal.

Caution:

WSRP-1.0 and WSRP-2.0 do not support portlets with Ajax features. However, WLP includes proprietary extensions in WSRP-2.0 to provide limited support for client rewriteable resource URLs. Some Ajax functionality can be supported if the container in use is the WebLogic Portal container.

8.15.2 Handling Errors

When moving to production, you want to make sure all possible errors are handled gracefully and the user will not see a stack trace. See Section 8.10, "Using Common WLP Features With JSF Portlets" for details.

8.15.3 Performance and Scalability

This section discusses best practices for developing efficient and scalable JSF portlets.

8.15.3.1 JSF Portlets in a Clustered Environment

WebLogic Portal runs on WebLogic Server, which includes industry-leading clustering technology. Clustering provides for both load balancing and failover capabilities. For the most part, WebLogic Server achieves both transparently. You do not need to know about the underlying clustering capabilities.

However, for failover to work properly, WebLogic Server replicates the user's HttpSession to a secondary node in the cluster. This enables the user to have a seamless experience if one node were to fail. But, in order for an HttpSession to be replicated without loss of data, the objects set as attributes within it must be serializable. For more information, see the section "Failover and Replication in a Cluster" in Oracle Fusion Middleware Using Clusters for Oracle WebLogic Server available at http://download.oracle.com/docs/cd/E12839_01/web.1111/e13709.pdf.

For JSF portlets to support failover, the JSF portlet state is written to the HttpSession object. Therefore, all JSF state objects must be serializable. Even request-scoped managed beans are written into the HttpSession in a portal environment. Therefore, it is a best practice for all managed beans, even those that are request scoped, to be serializable.

8.15.3.2 Portlet Render Caching

The WLP portal framework provides an easy solution for improving portlet rendering performance. The WLP Portlet Caching mechanism is the preferred way of handling caching, and not the JSR-286 suggested caching mechanism. When a portlet is not designed for user interaction or does not handle an interportlet communication event during the request, the portlet's markup can be served from cache. By default, a portlet's rendered markup is not cached. To enable portlet caching, set the following values in the Portlet Properties view: (see Figure 8-6).

  • Set the Render Cacheable property to true.

  • Set the Caches Expires property to the number of seconds to cache the portlet markup.

    Note:

    When a JSF portlet's markup is rendered from cache, none of the JSF life cycle methods are invoked during the request.

    Figure 8-6 Portlet Cache Configuration

    Description of Figure 8-6 follows
    Description of "Figure 8-6 Portlet Cache Configuration"

8.15.4 Securing JSF Portlets

This section discusses best practices for securing JSF portlets.

8.15.4.1 Deny Direct Access to the Portlet Views

To develop JSF portlets as standalone JSF applications, you must map the Faces servlet in web.xml, as shown in Example 8-37.

Example 8-37 Prefix Servlet Mapping in web.xml

<servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>faces</servlet-name>
    <url-pattern>*.faces</url-pattern>
</servlet-mapping>

Note that these mappings exist in web.xml only to support the direct access use case. Generally, in production it is not recommended to allow users to target the JSF views directly. It is better to force users to navigate to those views through the portal user interface. This can be enforced by removing the prefix and suffix mappings to the Faces servlet in web.xml.

8.15.4.2 Session Timeouts

It is a good practice to test the behavior of a web application for the request that immediately follows an HttpSession timeout. JSF portlets behave the same as traditional JSF applications during a session timeout in that the previous state of the portlet is not retained. Thus the user is taken back to the initial state of the JSF portlet just like it is in a JSF application. It is therefore important to ensure that your portal components re-render with the unauthenticated user in the session timeout use case.

8.15.5 Localizing JSF Portlets

This section discusses best practices and techniques for localizing JSF portlets prior to moving to production.

8.15.5.1 Configuring the Localization

When implementing localization, keep in mind that there are three different localization layers in the portal architecture. The first layer is of localization at the WLP portal level for books and pages. The second layer is of localization at the Java portlet level for title and description. The third layer is of localization at the JSF component level.

WLP provides portal localization for the .book and .page files. For detailed information, see the section "Localizing Titles for File-Based Books, Pages, and Portlets" in Oracle Fusion Middleware Portal Development Guide for Oracle WebLogic Portal.

The Java Portlet specification provides the localization for the title and description of the portlet. To ensure that your portlet works across different third-party portlet containers, the Java standard locale support should be used. This is accomplished by adding <supported-locale> to the portlet's entry in the portlet.xml file. For further details, see the JSR-286 specification at http://jcp.org/aboutJava/communityprocess/final/jsr286/index.html.

In addition, JSF provides localization for the JSF components within a JSF view using a locale pluggable interface. The ViewHandler interface has a method calculateLocale()that performs the localization functionality of the JSF display components. When developing JSF portlets, it is a best practice to create a bundle for each individual portlet definition. Or, if several portlets are always to be used together, a resource bundle can be shared between a group of portlets. This enables portlets to be reused more easily across portal projects.

Another best practice is to make sure WLP, JSF, and Java portlets are all configured with the same set of locales. This ensures a consistent localized experience for a rendered page.

8.16 Third-Party Libraries

This section includes the following:

8.16.1 Facelets

WLP does not support the use of Facelets with JSF 1.2. If you require adding Facelet support, the portlets must use the WLP native Faces bridge. See the section "Using Facelets" available at http://download.oracle.com/docs/cd/E13155_01/wlp/docs103/portlets/jsf_portlet_development.html#wp1040473.

8.16.2 Tomahawk

WLP does not officially support the use of Tomahawk components, so they are not included in the WebLogic Portal installation. This also means there are no assurances that all Tomahawk tags will work flawlessly within a WebLogic Portal environment. However, you can configure these components in the portal application and test them. It is recommended to use the latest Tomahawk version for JSF 1.2.

Follow these instructions to configure it:

  1. Download the Tomahawk JAR file for JSF 1.2: at least tomahawk12-1.1.10.jar or later.

  2. Copy the JAR file into WEB-INF/lib.

  3. In web.xml, add the following entries in the appropriate places.

    Example 8-38 web.xml Settings For Tomahawk

    <!-- Make entries that explicitly enable the portal-friendly changes
    introduced with latest versions of Tomahawk ->
    <context-param>
         <param-name>org.apache.myfaces.CHECK_EXTENSIONS_FILTER</param-name>
         <param-value>false</param-value>
    </context-param>
    <context-param>
         <param-name>
           org.apache.myfaces.DISABLE_TOMAHAWK_FACES_CONTEXT_WRAPPER
         </param-name>
         <param-value>false</param-value>
    </context-param>
    <!-- Configure the mechanism for bringing in resources (.js, .css). ->
    <context-param>
         <param-name>org.apache.myfaces.ADD_RESOURCE_CLASS</param-name>
         <param-value>
           org.apache.myfaces.renderkit.html.util.NonBufferingAddResource
         </param-value>
    </context-param>
    <!-- Map the resource loading capability of Tomahawk ->
    <!-- myfaces configuration -->
    <filter>
         <filter-name>MyFacesExtensionsFilter</filter-name>
    <filter-class>org.apache.myfaces.webapp.filter.ExtensionsFilter</filter-class>
        <init-param>
            <description>Set the size limit for uploaded files.
                Format: 10 - 10 bytes
                        10k - 10 KB
                        10m - 10 MB
                        1g - 1 GB
            </description>
            <param-name>uploadMaxFileSize</param-name>
            <param-value>20m</param-value>
        </init-param>
    </filter>
    <!-- extension mapping for adding <script/>, <link/>, and other resource tags to JSF-pages  -->
    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <!-- servlet-name must match the name of your javax.faces.webapp.FacesServlet entry -->
        <servlet-name>Faces Servlet</servlet-name>
    </filter-mapping>
    <!-- extension mapping for serving page-independent resources (javascript, stylesheets, images, etc.)  -->
    <filter-mapping>
        <filter-name>MyFacesExtensionsFilter</filter-name>
        <url-pattern>/faces/myFacesExtensionResource/*</url-pattern>
    </filter-mapping>
    

8.17 Tips for Logging, Iterative Development, and Debugging of JSF Portlets

For WebLogic Portal Web Projects, the integration of logging is pre-configured. The WebLogic Integrated Commons Logging facet is a required facet for any Portal Web Project.

Follow these steps to increase the log sensitivity level to enable Debug messages to be output to the console:

  1. Log on to the WebLogic Console, usually at a URL like: http://localhost:7001/console.

  2. Navigate to Servers > AdminServer > Logging tab.

  3. Click the Advanced link to get the full set of controls.

  4. In the Log file section, set the Severity Level to Debug.

  5. In the Standard out section, set the Severity Level to Debug.

  6. Click Save.

  7. On the next request to a portal page that contains JSF portlets, you will see debug output on the server console window.

8.17.1 Using Iterative Development for JSF Portlets

This section discusses techniques for iterative development of JSF portlets.

8.17.1.1 Testing Outside of the Portlet Container

Sometimes it is desirable to test the JSF portlet view outside of the portlet container. In other words, it is possible to target the view URL directly like a standard JSF application does. If the JSF view can execute without the portal, then this is a good way to debug issues with the JSF code. Targeting the view file directly isolates the JSF container from the portlet container, so it helps in analyzing and fixing problems. See Section 8.15.4, "Securing JSF Portlets" for more details on how to map the Faces servlet in web.xml.

8.17.1.2 Using Application Republish

WebLogic Server automatically republishes changes to JSP files. However, if auto publishing is disabled, you must explicitly republish the changes to source code or deployment descriptors from the Server pane in Eclipse (among other ways). This process is not specific to Portal Web Projects.

8.17.1.3 HttpSession Caching

JSF caches the user's views in the HttpSession. Therefore, while WebLogic Server detects that a JSP has been updated, any existing session contains an outdated copy of the view. It is therefore necessary to begin a new HttpSession after modifying a JSF JSP. This issue is not specific to Portal Web Projects.

8.17.1.4 Handling OutOfMemory Errors

Unfortunately, certain implementations of JSF have memory leaks that occur during a web application redeploy. During long development sessions across many redeployments, the server may fail with an OutOfMemoryException. Therefore, you must restart the server when this exception occurs. This issue is not specific to Portal Web Projects.

8.17.2 Debugging

This section discusses how to use the Eclipse debugger to troubleshoot JSF portlets. See the Eclipse documentation for information on enabling the Eclipse debugger.

When debugging a portlet, usually the best place to start is to set breakpoints in the entire code, including managed bean methods as well as subclassed Java portlet code. But sometimes you need to look into the portal framework. This is because the JSF bridge invokes the JSF implementation, which in turn processes and renders the portlet. For this reason, you should set break points in the JSF implementation and within the JSF bridge as well. Source code is available for the open source JSF implementations and JSR-329 bridge implementation.

This section includes the following:

8.17.2.1 Attaching Source (Step 1)

You can investigate resources on the web that explain how to attach source code to the JAR files in your project (for example, you can search for "eclipse attach source"). The main issue for JSF development is locating the proper source files for the JSF implementation used in your web project.

You can download the Sun reference implementation (RI) code from the Mojarra project site at https://javaserverfaces.dev.java.net.

8.17.2.2 Suggested JSF Framework Break Points (Step 2)

The following list provides some JSF implementation break points to get started (assumes Sun RI):

  • *com.sun.faces.lifecycle.LifecycleImpl.execute() - The front door to all JSF processing, a good place to start.

  • *com.sun.faces.lifecycle.RestoreViewPhase.execute() – Restores the correct view; useful if the portlet is rendering the wrong view.

  • *com.sun.faces.lifecycle.InvokeApplicationPhase.execute() - Invokes an action; useful when diagnosing issues invoking action methods.

8.18 Appendix: JSFJavaPortletHelper

You may find it helpful to create a helper class to develop the common functionality that you can reuse in your portlets. Example 8-39 shows how you can implement a helper class. This class is a concrete code example of many of the concepts discussed in this chapter. Use at your own discretion.

Example 8-39 JSFJavaPortletHelper Class

package oracle.samples.wlp.jsf;
import java.security.Principal;
import java.util.ResourceBundle;
import javax.faces.context.FacesContext;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletContext;
import javax.portlet.PortletRequest;
import javax.portlet.PortletPreferences;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.PortletResponse;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.namespace.QName;
import oracle.samples.wlp.jsf.portlets.login.LoginServlet;
import weblogic.servlet.security.ServletAuthentication;
import com.bea.netuix.servlets.controls.portlet.PortletPresentationContext; 
import com.bea.netuix.servlets.controls.portlet.backing.PortletBackingContext;
import com.bea.netuix.servlets.manager.AppContext;
/**
 * A helper class with examples of many useful methods for JSF portlets. These
 * methods are expected to be called from JSF managed beans.
 * This is to aid in the development of JSF portlets.
 */
public class JSFJavaPortletHelper {
    // STANDARD CONTEXT
    /**
     * Gets the HttpServletRequest from the FacesContext.
     * Must only be called from a JSF managed bean.
     * @return an HttpServletRequest implementation
     */
    static public HttpServletRequest getServletRequest() {
        HttpServletRequest httpServletRequest = null;
        FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getRequest();
        //how jsr329 bridge finds the request, another way is to dispatch to a servlet or jsp
        if (obj instanceof PortletRequest){
            PortletRequest pr = (PortletRequest) obj;
            httpServletRequest = (HttpServletRequest)
 pr.getAttribute("javax.servlet.request");
        }
        //how native bridge finds the request
        else if (obj instanceof HttpServletRequest){
            httpServletRequest = (HttpServletRequest) obj ;
        }
        return httpServletRequest;
    }
    /**
     * Gets the HttpSession from the FacesContext.
     * Must only be called from a JSF managed bean.
     *
     * @return a HttpSession implementation
     */
    static public HttpSession getSession() {
        HttpServletRequest request = getServletRequest();
        return request.getSession();
    }
    /**
     * Gets the HttpServletResponse from the FacesContext.
     * Must only be called from a JSF managed bean.
     *
     * @return a HttpServletResponse implementation
     *
     */
    static public HttpServletResponse getServletResponse() {
        HttpServletResponse httpServletResponse = null;
        FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getRequest();
        //how jsr329 bridge finds the response, another way is to dispatch to a servlet or jsp
        if (obj instanceof PortletRequest){
            PortletRequest pr = (PortletRequest) obj;
            httpServletResponse = (HttpServletResponse)
pr.getAttribute("javax.servlet.response");
        }
        //how native bridge finds the request
        else {
                obj = fc.getExternalContext().getResponse();
            httpServletResponse = (HttpServletResponse) obj ;
        }
        return httpServletResponse;
    }
        /**
     * Gets the PortletResponse from the FacesContext. Only valid when using the JSR329-bridge.
     * 
     * @return PortletResponse
     *
     */
    static public PortletResponse getPortletResponse() { 
    
    FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getResponse();
        if (obj instanceof PortletResponse){
        return (PortletResponse)obj;
        }
        else {
        return null;
        }
    }
   
    /**
     * Gets the localized resource bundle using the passed bundle name
     * Must only be called from a JSF managed bean.
     *
     * @param bundleName the String name of the bundle
     * @return the ResourceBundle containing the localized messages for the
     */
    static public ResourceBundle getBundle(String bundleName) {
        FacesContext context = FacesContext.getCurrentInstance();
        ResourceBundle bundle =
ResourceBundle.getBundle(bundleName,context.getViewRoot().getLocale());
        return bundle;
    }
    /**
     * Gets the localized message using the passed bundle name and message
     * Must only be called from a JSF managed bean.
     *
     * @param bundleName the String name of the bundle
     * @param messageKey the String key to be found in the bundle properties
     * @return the String containing the localized message
     */
    static public String getBundleMessage(String bundleName, String
            messageKey) {
        String message = "";
        ResourceBundle bundle = getBundle(bundleName);
        if (bundle != null) {
            message = bundle.getString(messageKey);
        }
        return message;
    }
    // *************** PORTAL ENVIRONMENT **************//
    //Note: Although these methods show getting the actual Servlet request from the PortletRequest, another way to do this 
    //would be to dispatch to an actual Servlet that then gets an instance of the PortletBackingContext and 
    //PortletPresentationContext.  This latter way may be more portable and isolate your WLP specific code better.
      
    /**
     * Gets the PortletBackingContext object. This method will return null
     * if called during the RENDER_RESPONSE JSF lifecycle.
     * Must only be called from a JSF managed bean.
     *
     * @return the active PortletBackingContext, or null
     */
    static public PortletBackingContext getPortletBackingContext() {
        return
 PortletBackingContext.getPortletBackingContext(getServletRequest());
    }
    /**
     * Gets the PortletPresentationContext object. This method will return
     * if NOT called during the RENDER_RESPONSE JSF lifecycle.
     * Must only be called from a JSF managed bean.
     *
     * @return the active PortletPresentationContext, or null
     */
    static public PortletPresentationContext getPortletPresentationContext() {
        HttpServletRequest request = getServletRequest();
        return PortletPresentationContext.getPortletPresentationContext(request);
    }
    /**
     * Returns true if the user can make customizations
     * (preferences, add/move/remove portlets, add pages) to the portal.
     * This is based on factors such as: is the user authenticated,
     * is it a streaming portal (not a .portal file),
     * and customization is enabled in netuix-config.xml.
     * Can be called from any web application class.
     *
     * @return a boolean, true if it is possible for the user to make customizations
     */
    static public boolean isCustomizable() {
        return AppContext.isCustomizationAllowed(getServletRequest());
    }
    // *****  AUTHENTICATION ******///
    //The following are authentication methods that are used in the Login/Logout Example
    /**
     * Is the current user authenticated?
     * Must only be called from a JSF managed bean.
     *
     * @return true if the user is authenticated, false if not
     */
    static public boolean isAuthenticated() {
        Principal principal =
FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        return principal != null;
    }
    
    /**
     * Is the current user authenticated?
     * This checks an attribute set on the PortletRequest by the LoginServlet, whether
     * the user is authenticated.
     *
     * @return true if the user is authenticated, false if not
     */
    static public boolean isAuthenticatedViaAttribute() {
        PortletRequest pr =
(PortletRequest)(FacesContext.getCurrentInstance().getExternalContext().getRequest());
        Boolean authenticated= ((Boolean)
pr.getAttribute(LoginServlet.AUTHENTICATED));
        return authenticated.booleanValue();
    }
    /**
     * Get the current user's username from the container.
     * Must only be called from a JSF managed bean.
     *
     * @return the user name, null if the user is not authenticated
     */
    static public String getUsername() {
        String username = null;
        Principal principal =
            FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        if (principal != null) {
            username = principal.getName();
        }
        return username;
    }
    /**
     * Get the current user's username for display. If the user is not authenticated, it
     * will return the name passed as the anonymousUsername parameter.
     * DO NOT use this method
     * for anything other than display (e.g. access control, auditing, business logic),
     * as the passed anonymous name may conflict with an actual username in the system.
     * Must only be called from a JSF managed bean.
     *
     * @param anonymousUsername a String localized name to use for an anonymous user, like "Guest"
     * @return the user name
     */
    static public String getUsernameForDisplay(String anonymousUsername) {
        String username = anonymousUsername;
        Principal principal =
FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
        if (principal != null) {
            username = principal.getName();
        }
        return username;
    }
    // USER AUTHENTICATION METHODS
    /**
     * Authenticate the user with WebLogic Server
     * See <code> authenticate_generic </code> for using a serlvet to do authentication.
     *
     * @param username the String username
     * @param password the String password as provided by the user
     * @return true if the login was successful, false if not
     */
    static public boolean authenticate(String username, String password) {
        HttpServletRequest httpServletRequest = getServletRequest();
        HttpServletResponse httpServletResponse = getServletResponse();
        //wlp specific way of authentication
        int result = ServletAuthentication.weak(username, password, httpServletRequest, httpServletResponse);
               //redirect the page, so any customization for this user is picked up after successful login
        if (result != ServletAuthentication.FAILED_AUTHENTICATION) {            Object obj =
 FacesContext.getCurrentInstance().getExternalContext().getResponse();
            if (obj instanceof ActionResponse){
                ActionResponse ar = (ActionResponse) obj;
                ar.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal", "framework.redirectBeforeRender"),null);
            }
        }
        return result != ServletAuthentication.FAILED_AUTHENTICATION;
    }
        /**
     * This will authenticate the user putting the WLS specific authentication process in a servlet.
     * Thus isolating container specific code better.
     * It calls to a LoginManager servlet to do the authentication.
     * If the environment is not using the standard JSR329-bridge, it will default to WLP specific authentication.
     * If authentication is successful, it will then set an event using JSR286 style eventing, to request a redirect before render 
     * so that any personal specific components will be re-rendered.
     * @param username of user to authenticate
     * @param password of user to authenticate
     * @return true to indicate username/password has been authenticated, false if it failed.
     * 
     */
    static public boolean authenticate_generic(String username, String password) {
        HttpServletRequest httpServletRequest = null;
        HttpServletResponse httpServletResponse = null;
        FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getContext();
        //how jsr329 bridge finds the request
        if (obj instanceof PortletContext){
            PortletContext pc = (PortletContext) obj;
            PortletRequestDispatcher prdispatcher =
pc.getNamedDispatcher("LoginServlet");
            try{
                prdispatcher.include((PortletRequest)fc.getExternalContext().getRequest(),
                    (PortletResponse)fc.getExternalContext().getResponse());
            }
            catch(Exception e) {
                //MODIFY :  user proper logging methods
                System.out.println("Exception on dispatch:" + e.toString() );
                e.printStackTrace();
                return false;
            }
        }
        //how native bridge finds the request & response
        else if (obj instanceof ServletContext){
            httpServletRequest = (HttpServletRequest)
fc.getExternalContext().getRequest() ;
            httpServletResponse = (HttpServletResponse)
 fc.getExternalContext().getResponse();
            //wlp specific way of authentication
            ServletAuthentication.weak(username, password, httpServletRequest, httpServletResponse);
        }
       //redirect the page, so any customization for this user is picked up after successful login
        if (isAuthenticated()) {
            obj = fc.getExternalContext().getResponse();
            ActionResponse ar = (ActionResponse) obj;
            ar.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal", "framework.redirectBeforeRender"),null);
            return true;
        }
        else {
            return false;
        }
            }
        /** 
     * Logout the user invalidating the session object directly and then send event to redirect.
     * See <code> logout_generic </code> for using a serlvet to do un-authentication.
     * Call this if using the jsr329 bridge, otherwise use a backing file     */
    static public boolean logout() {
        FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getResponse();
        if (obj instanceof ActionResponse){
            HttpSession session = getSession();
            session.invalidate();
            ActionResponse ar = (ActionResponse) obj;
            ar.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal", "framework.redirectBeforeRender"),null);
            return true;
        }
        else {
            return false;
        }
            }
    
    /**
     * Logout the user invalidating the session object through the use of a servlet.
     * Send event to redirect after un-authenticating the user.
     * Call this if using the jsr329 bridge, otherwise use a backing file
     *
     **/
    static public boolean logout_generic() {
        FacesContext fc = FacesContext.getCurrentInstance();
        Object obj = fc.getExternalContext().getContext();
        //how jsr329 bridge finds the request, wlp specific implementation
        if (obj instanceof PortletContext){
            PortletContext pc = (PortletContext) obj;
            PortletRequestDispatcher prdispatcher =
pc.getNamedDispatcher("LoginServlet");
            try{
                prdispatcher.include((ActionRequest)fc.getExternalContext().getRequest(),
                    (ActionResponse)fc.getExternalContext().getResponse());
            }
            catch(Exception e) {
                //MODIFY :  user proper logging methods
                System.out.println("Exception on dispatch:" + e.toString() );
                e.printStackTrace();
                return false ;
            }
        } else {
            return false;
        }
        //check the attribute the servlet set
        boolean authorized = isAuthenticatedViaAttribute();
        if (!authorized) { //logout was successful
            obj = fc.getExternalContext().getResponse();
            ActionResponse ar = (ActionResponse) obj;
            ar.setEvent(new QName("urn:com:oracle:wlp:netuix:event:portal", "framework.redirectBeforeRender"),null);
        }
        return authorized;
    }
        // NAMESPACES AND LABELS
    /**
     * Gets the current portlet's instance label.
     * Must only be called from a JSF managed bean.
     *
     * @return the String instance label
     */
    static public String getInstanceLabel() {
        return getInstanceLabel(getServletRequest());
    }
    /**
     * Gets the current portlet's instance label.
     * Can be called from any web application class.
     *
     * @param the HttpServletRequest object
     * @return the String instance label
     */
   static public String getInstanceLabel(HttpServletRequest request) {
        String label = "_global";
        PortletBackingContext pbc =
PortletBackingContext.getPortletBackingContext(request);
        if (pbc != null) {
            label = pbc.getInstanceLabel();
        }
        else {
            PortletPresentationContext ppc = PortletPresentationContext.getPortletPresentationContext(request);
            if (ppc != null) {
                label = ppc.getInstanceLabel();
            }
        }
        return label;
    }
    /**
     * Gets the current portlet's definition label.
     * Must only be called from a JSF managed bean.
     *
     * @return the String definition label
     */
    static public String getDefinitionLabel() {
        return getDefinitionLabel(getServletRequest());
    }
    /**
     * Gets the current portlet's definition label.
     * Can be called from any web application class.
     *
     * @param the HttpServletRequest object
     * @return the String definition label
     */
    static public String getDefinitionLabel(HttpServletRequest request) { String label = "_global";
    PortletBackingContext pbc = PortletBackingContext.getPortletBackingContext(request);
    if (pbc != null) {
        label = pbc.getDefinitionLabel();
    }
    else {
        PortletPresentationContext ppc =
            PortletPresentationContext.getPortletPresentationContext(request);
        if (ppc != null) {
            label = ppc.getDefinitionLabel();
        }
    }
    return label;
    }
    // ****   PORTLET PREFERENCE METHODS  **** //
    /**
     * Gets an instantiated preferences object for the portlet;
     * it must be obtained once per request.
     * Must only be called from a JSF managed bean.
     * Only works with JSR-329 bridge
     *
     * @return the PortletPreferences object for the request
     */
    static public PortletPreferences getPreferencesObject() {
    FacesContext fc = FacesContext.getCurrentInstance();
        PortletRequest pr = (PortletRequest) fc.getExternalContext().getRequest();
        return pr.getPreferences();
    }
    /**
     * Gets the single value preference.
     *
     * @param name the String name of the preference
     * @param value the String default value to use if the preference isn't
     * @return the String value
     */
    static public String getPreference(PortletPreferences prefs, String name,
            String value) {
        if (prefs != null) {
            value = prefs.getValue(name, value);
        }
        return value;
    }
    /**
     * Sets a single value preference into the preferences object.
     * storePreferences() must be called subsequently to persist the change.
     *
     * @param name the String name of the preference
     * @param value the String value of the preference
     */
    static public void setPreference(PortletPreferences prefs, String name, String value) {
        if (prefs != null) {
            try {
                prefs.setValue(name, value);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * After setting updated values into the preferences object, call this
     * method so they can be stored in the persistent store in a single atomic
     * operation.
     *
     * @param prefs the PortletPreferences to be persisted
     * @return a boolean, true if the store succeeded
     */
    static public boolean storePreferences(PortletPreferences prefs) {
        if (!isCustomizable()) {
            return false;
        }
        try {
            prefs.store();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}