When a user requests a portal page, the portal asks the portlet container to generate the user interface for each portlet on the page. The portal creates the page by aggregating the fragments that the portlets generate, and returns the page to the client for the user to see.
To generate the user interface of a specific portlet, the portlet container invokes the portlet’s render() method. In GenericPortlet, the render() method dispatches the method call to the doView(), doEdit(), or doHelp() method depending on the portlet's mode. These methods typically execute user interface-related logic before dispatching the request to a JavaServer Page (JSP), which defines the markup for the portlet fragment.
Flex integrates seamlessly in this workflow. The major difference when using Flex to render the portlet user interface is that, instead of writing traditional HTML markup in the JSP, you simply embed the Flex application. The easiest way to embed a Flex application in a JSP is to use the MXML tag of the JSP tag library provided with Flex (see helloworld.jsp below). Alternatively, you can also manually code the HTML Object tag to embed the Flex application in the page.
Note: With the Flex JSP tag library, you can inline MXML (the Flex markup language) into a JSP, as opposed to pointing to an external MXML file.
The following example demonstrates a Flex-based Hello World portlet.
Listing 1: HelloWorldPortlet.java
package samples.portlet;
import javax.portlet.*;
import java.io.IOException;
public class HelloWorldPortlet extends GenericPortlet {
public void doView (RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/jsp/helloworld.jsp");
rd.include(request,response);
}
}
Listing 2: helloworld.jsp
<%@ taglib uri="FlexTagLib" prefix="mm" %> <mm:mxml source="/jsp/helloworld.mxml"/>
Listing 3: helloworld.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" width="200" height="100">
<mx:Label text="Hello World!"/>
</mx:Application>
Of course, you don't need Flex to display “Hello World!” The point is that this is all you need to create a rich user interface. At this point, you could modify helloworld.mxml to create a complete Rich Internet Application (using DataGrids, Trees, Charting Components, Drag and Drop behaviors, and so forth) rendered as a portlet in your portal application.
In the traditional portlet workflow, the portlet acts as a mini front controller: All the requests for processing actions and for rendering the user interface are routed through the portlet class using portlet URLs. The portlet then delegates the request to Model (for example, a JavaBean, an EJB, or a web service) and View components (for example, a JSP or a servlet). Portlet URLs are opaque URLs that the portlet container generates. There are two types of portlet URLs: action URLs or render URLs.
Even though Flex provides more efficient approaches—both from a user experience and a bandwidth point of view—to communicate with your portal back end, Flex-based portlets support this front-controller workflow. You can pass action and render URLs as parameters to the Flex application. The Flex application can then use these URLs to send requests to the portal, just like a traditional HTML-based portlet fragment would do.
The following example (Listing 4) demonstrates a Flex-based portlet using action and render URLs.
Listing 4: URLDemoPortlet.java
package samples.portlet;
import javax.portlet.*;
import java.io.IOException;
public class URLDemoPortlet extends GenericPortlet {
public void doView (RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PortletURL actionURL = response.createActionURL();
actionURL.setPortletMode(PortletMode.VIEW);
request.setAttribute("actionURL", actionURL.toString());
PortletURL renderURL = response.createRenderURL();
renderURL.setPortletMode(PortletMode.VIEW);
request.setAttribute("renderURL", renderURL.toString());
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/jsp/urldemo.jsp");
rd.include(request,response);
}
}
Listing 5: urldemo.jsp
<%@ taglib uri="FlexTagLib" prefix="mm" %>
<mm:mxml source="/jsp/urldemo.mxml">
<mm:param name="actionURL" value="<%= request.getAttribute("actionURL") %>" />
<mm:param name="renderURL" value="<%= request.getAttribute("renderURL") %>" />
</mm:mxml>
Note: You can use the same parameter passing technique to pass any other contextual information to the Flex application: portlet initialization parameters, preferences, and so forth.
Listing 6: urldemo.mxml
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml" xmlns="*"
height="300" width="800" backgroundColor="#FFFFFF">
<mx:Script>
var actionURL: String;
var renderURL: String;
</mx:Script>
<mx:Label text="{actionURL}"/>
<mx:Label text="{renderURL}"/>
<mx:Button label="Request Action URL" click="getUrl(actionURL)"/>
<mx:Button label="Request Render URL" click="getUrl(renderURL)"/>
</mx:Application>
This example's portlet URLs workflow is primarily based on HTML clients operating in a traditional request/response model. The limitation of this model is that it is page-centric and that the user interface (in this case, the portal page) must refresh in response to each client request. This is both disorienting from a user experience point of view and sub-optimal from a bandwidth usage point of view. When using a rich client technology, that limitation goes away: you can communicate with back-end services in a service-oriented architecture (SOA) using XML over HTTP or SOAP without the need for refreshing the user interface. I discuss this SOA approach in the next section.
However, the ability for a Flex application to work with action and render URLs can sometimes prove useful. For example, a Flex application might use a render URL to ask the portlet container to change its window state.
Flex clients can communicate with back-end services in a service-oriented architecture. Flex provides three different data services to accommodate the specific data access requirements of your application:
The following example demonstrates a Flex-based Stock Quote portlet using a web service.
Listing 7: StockQuotePortlet.java
package samples.portlet;
import javax.portlet.*;
import java.io.IOException;
public class StockQuotePortlet extends GenericPortlet {
public void doView (RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PortletRequestDispatcher rd = getPortletContext().getRequestDispatcher("/jsp/stockquote.jsp");
rd.include(request,response);
}
}
Listing 8: stockquote.jsp
<%@ taglib uri="FlexTagLib" prefix="mm" %> <mm:mxml source="/jsp/stockquote.mxml"/>
Listing 9: stockquote.mxml
<?xml version="1.0" encoding="UTF-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"
width="300" height="200"
backgroundColor="#FFFFFF">
<mx:WebService id="ws"
wsdl="http://services.xmethods.net/soap/urn:xmethods-delayed-quotes.wsdl">
<mx:operation name="getQuote">
<mx:request>
<symbol>{symbol.text}</symbol>
</mx:request>
</mx:operation>
</mx:WebService>
<mx:TextInput id="symbol"/>
<mx:Button label="Get Quote" click="ws.getQuote.send()"/>
<mx:Label text="{ws.getQuote.result}"/>
</mx:Application>
Flex applications leverage the Macromedia Flash player sandbox environment. In this model, the client application can only communicate with the server that served it. You access the data access services described above (WebService, RemoteObject, and HTTPService) through a proxy servlet on that server. The proxy servlet intercepts requests to WebServices, HTTPServices, and RemoteObjects, redirects the requests appropriately, and then returns the responses to the client. You can secure access to the proxy servlet URLs through traditional J2EE security APIs or using a third-party security infrastructure, such as Netegrity SiteMinder.
Flex provides a session API that Flex client applications can use to access (set and get) attributes in the portlet session object.
Listing 10: The following example demonstrates a Flex-based portlet getting and setting a session attribute value.
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.macromedia.com/2003/mxml"/>
<mx:RemoteObject id="sessionObj" source="servlet" showBusyCursor="true"/>
<mx:HBox>
<mx:TextInput id="fromSession" text="{sessionObj.session.result}"/>
<mx:Button label="Get userName Session Attribute" click="sessionObj.session('get', 'userName')"/>
</mx:HBox>
<mx:HBox>
<mx:TextInput id="toSession"/>
<mx:Button label="Set userName Session Attribute"
click="sessionObj.session('set', 'userName', toSession.text)"/>
</mx:HBox>
</mx:Application>
You deploy the Flex presentation server as a web application inside your application server. You can package Flex as part of the portlet web application, or you can deploy Flex as a separate web application. I have tested the examples in this article in these two configurations.