Spring Portlet MVC Framework Information

In 2007 i wrote following 3 part series on how to use Spring Portlet MVC Framework for IBM's developerworks. That series was based on Spring Framework 2.0.8


  1. Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal: Introduction to Spring Portlet MVC Framework

  2. Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal: Handling form submissions

  3. Developing a Spring Portlet MVC Framework application for use inside IBM WebSphere Portal: Advanced Spring Portlet MVC Framework



Starting from Version 3.0.1, Spring Portlet MVC Framework started supporting Portlet Specification 2.0, so i did spent some time playing with it and this is list of information on my blog about the Spring Portlet MVC Framework 3.0.1

Handling actions in Spring Portlet MVC Framework

In the HelloWorld Spring Portlet MVC Framework 3.0.1 entry, i covered the steps required to create simple HelloWorld portlet, that will forward control to a JSP in the view mode, but that portlet does not support action requests. I built a HelloSpring31ActionPortlet to demonstrate how to handle action request in the portlet.

The HelloSpring31ActionPortlet portlet supports two modes VIEW and EDIT. It displays a form in the EDIT mode where user can enter value for userName and when user submits the form it will save that value in the userName preference. Then in the VIEW mode it reads that value and shows a customized greeting message to the user.

I had to follow these steps to build this application


  • First i built this EditController.java, which will be responsible for handling requests when the portlet is invoked in the EDIT mode

    package com.webspherenotes.mvc.spring.action;

    import javax.portlet.ActionRequest;
    import javax.portlet.ActionResponse;
    import javax.portlet.PortletMode;
    import javax.portlet.PortletPreferences;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    import org.springframework.web.portlet.ModelAndView;
    import org.springframework.web.portlet.mvc.AbstractController;

    public class EditController extends AbstractController{
    public void handleActionRequest(ActionRequest request,
    ActionResponse response) throws Exception {
    System.out.println("Entering EditController.handleActionRequest");
    String userName = request.getParameter("userName");
    PortletPreferences preferences = request.getPreferences();
    preferences.setValue("userName", userName);
    preferences.store();
    response.setPortletMode(PortletMode.VIEW);
    System.out.println("Exiting EditController.handleActionRequest");
    }
    public ModelAndView handleRenderRequest(RenderRequest request,
    RenderResponse response) throws Exception {
    System.out.println("Entering EditController.handleRenderRequest");
    ModelAndView modelAndView = new ModelAndView("edit");
    System.out.println("Exiting EditController.handleRenderRequest");
    return modelAndView;
    }
    }


    The EditController has two methods

    1. handleActionRequest: This method gets called whenever you try to access the actionURL pointing to the Edit mode of the portlet. Inside this method you get access to ActionRequest and ActionResponse object, i am using this opportunity to read the value of userName parameter submitted by user and setting it in preference

    2. handleRenderRequest: This method gets called to get markup for edit mode of the portlet. I am using it for forwarding control to edit.jsp




  • This how the edit.jsp page looks like

    <%@page language="java" contentType="text/html; %>
    <%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
    <portlet:defineObjects />
    <form method="POST" action="<portlet:actionURL/>">
    <table>
    <tr>
    <td>User Name</td>
    <td><input type="text" name="userName" /></td>
    </tr>
    <tr>
    <td><input type="submit" name="submit" /></td>
    </tr>
    </table>
    </form>

    As you can see this JSP is similar to any other portlet JSP, all that it is doing is submitting a form to actionURL


  • This is how the ViewController.jsp for my portlet looks like

    package com.webspherenotes.mvc.spring.action;
    import javax.portlet.RenderRequest;
    import javax.portlet.RenderResponse;
    import org.springframework.web.portlet.ModelAndView;
    import org.springframework.web.portlet.mvc.AbstractController;
    public class ViewController extends AbstractController{
    public ModelAndView handleRenderRequest(RenderRequest request,
    RenderResponse response) throws Exception {
    System.out.println("Entering ViewController.handleRenderRequest()");
    ModelAndView modelAndView = new ModelAndView("view");
    modelAndView.addObject("userName",
    request.getPreferences().getValue("userName", "User Name is not set"));
    System.out.println("Exiting ViewController.handleRenderRequest()");
    return modelAndView;
    }
    }


    The ViewController class has only handleRenderRequest method and it does not support actionURl being called for view mode. In the handleRenderRequest i am reading value of the userName preference setting it in the request object by adding it in the ModelAndView and then forwarding control to view.jsp


  • This is how the view.jsp looks like

    <%@page language="java" contentType="text/html; %>
    <%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
    <portlet:defineObjects />
    <h1>Hello <%=renderRequest.getAttribute("userName") %></h1>

    Here i am reading the value of userName attribute from request and then using it build customized greeting for user


  • This is how the spring configuration for my portlet looks like, as you can see i have two beans for two different modes and then portletModeHandlerMapping is used for mapping the bean name to the mode

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <bean id="viewController"
    class="com.webspherenotes.mvc.spring.action.ViewController" />

    <bean id="editController"
    class="com.webspherenotes.mvc.spring.action.EditController" />

    <bean id="portletModeHandlerMapping"
    class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
    <property name="order" value="1" />
    <property name="portletModeMap">
    <map>
    <entry key="view">
    <ref bean="viewController" />
    </entry>
    <entry key="edit">
    <ref bean="editController" />
    </entry>
    </map>
    </property>
    </bean>
    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass">
    <value>org.springframework.web.servlet.view.JstlView</value>
    </property>
    <property name="prefix">
    <value>/WEB-INF/jsp/</value>
    </property>
    <property name="suffix">
    <value>.jsp</value>
    </property>
    </bean>
    </beans>


Client profile information (CC/PP) in portlets

For each incoming request, the portal tries to determine the client that issued the request. It is important to determine the client in order to know its capabilities and respond properly. The portal database contains a repository of client profiles, providing all relevant information about the supported clients. The Portal uses JSR 188, which provides a standard API named "CC/PP" for accessing client profiles. The Java Portlet Specification allows portlets to access the client profile through a request attribute. The Getting Started With Composite Capabilities/Preference Profiles and JSR 188 has more information about CC/PP

I wanted to learn how the CC/PP works so i built this sample portlet, which queries list of all the profile attributes and then prints the attributes and there values in table format like this. You can download the sample code from here



This is source code of the portlet


package com.webspherenotes.misc;

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import javax.ccpp.Attribute;
import javax.ccpp.Component;
import javax.ccpp.Profile;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class CPIPortlet extends GenericPortlet{
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering CPIPortlet.doView()");
response.setContentType("text/html");
Profile clientProfile =
(Profile) request.getAttribute(PortletRequest.CCPP_PROFILE);
System.out.println("Profile Object " + clientProfile);
HashMap attributeMap = new HashMap();
if(clientProfile != null){
processProfile(clientProfile );
Iterator attributeIt = clientProfile.getAttributes().iterator();
while(attributeIt.hasNext()){
Attribute attribute = attributeIt.next();
if(attribute != null){

System.out.println(attribute.getName() + " = " + attribute.getValue());
attributeMap.put(attribute.getName(), attribute.getValue());
}
}
}
System.out.println("Attribute Map " + attributeMap);
request.setAttribute("clientProfileAttributeMap", attributeMap);
getPortletContext().getRequestDispatcher("/index.jsp").include(request, response);
System.out.println("Entering CPIPortlet.doView()");
}
public void processProfile(Profile profile) {
System.out.println("Entering processProfile");
Set comps = profile.getComponents();
for(Iterator i = comps.iterator(); i.hasNext(); ) {
Component comp = (Component) i.next();
System.out.println("Component: " + comp.getName());
Set attrs = comp.getAttributes();
for(Iterator j = attrs.iterator(); j.hasNext(); ) {
Attribute attr = (Attribute) j.next();
Object value = attr.getValue();
System.out.println("\tAttribute: " + attr.getName() +
" = " + attr.getValue());
}
}
System.out.println("Entering processProfile");
}
}


In the doView() method of the CPIPorltet i am reading the PortletRequest.CCPP_PROFILE attribute from the PortletRequest and then i am using the Profile attribute to first find out list of the attributes and then generating table of this data using JSP

Restricting movability of portlet by width

In Setting width of portlet column in WebSphere Portal entry i did explain how to set width of vertical container, Now the next question is how do i make sure that if my portlet requires say 600px to display markup, user does not drag it into container which is only 300 px in size. In other words how do i restrict where user is able to drag the portlet.

By default the WPS wont check width of portlet before either adding or moving portlet to container so you will have to follow these steps to enable that support

First go the Configure Mode in the Edit layout portlet and check "Check portlets width before adding or moving portlets to a column" Check box like this


Then go the WebSphere Application Server Admin Console for WebSphere Portal server and go to Resource Environment Provider -> WP_ConfigService and add a Custom Property like this



Property Name -> PortletPlacementFilterImpl
Property Value -> com.ibm.wps.model.filters.portletplacement.impl.WidthFilterImpl

Save your changes and restart the WebSphere Portal Server


Follow the steps described in the Setting width of portlet column in WebSphere Portal entry to set width for the vertical column.

Last step would be to set what is the width of portlet or putting restrictions on the portlet, that you can do by setting a MAX_WIDTH preference like this



Now if you try, you wont be able to drag or add this portlet which has MAX_WIDTH set to 500px to any container with width less than 500 px. If you try that the portlet wont get dragged to the smaller container but no error is displayed to user, but if you look inside the SystemOut.log you will see this error

Setting width of portlet column in WebSphere Portal

WebSphere Portal allows you to set width of a vertical column on portal page. Ex. I did create a page which has 2 columns and width of the left column is 300px and width of right hand column is 600px, now if i add two portlets on a page and the portlets dont have any width restriction then my screen looks like this



If you dont set width of vertical container explicitly then IBM skin wont set any width and the portlets will have width based on the markup they are generating, sometimes this might generate unpredictable or unexpected output

You will have to follow these steps for setting width of vertical container, first go to the Manage pages portlet and find the page where you want to set width. Then click on the Edit Layout button, Check if you get a Show layout tools link on the top like this



If not then you might not have enabled the Show layout tools option, you can enable it by going to configure mode of the Edit Layout portlet like this



Now select the "Show toggle link for Show layout tools/hide layout tools" select box, save your changes and come back to the view mode. Now you will see the Show layout tools link at the top, click on the button and you will get a UI where you will be able to set width of vertical container by clicking on width



After setting Width and setting changes go back to the page and you should see your changes

Important Note : The way this feature is implemented is that, WebSphere Portal maintains Layout Metrics for every page. When you set width either through Admin UI or using Controller SPI the width gets stored in db. Then your UnlayeredContainer-H.jsp in your Skin will have to implement logic to read the width set in Layout Metrics and set it while generating vertical column. This is the code in IBM skin


<%
hasChildren=true;
String columnWidth=(String)currentLayoutNode.getMetrics().getValue(CompositionMetrics.WIDTH);
%>
<td valign="top" <% if (columnWidth != null)
{
out.print ("width=\"");
out.print (columnWidth);
out.print ("\"");
} %>>

Reading query string inside the Flex Portlet

I made some changes in the Getting Query String of portal URL from inside the portlet code to use Flex on the client side. Now Flex is used for UI on the client side. You can download the sample code for portlet from here



The Portlet code remains the same, except one change, now i am forwarding control to query.jsp which is including Flex object on page using code like this


<%@page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<portlet:defineObjects />
<script type="text/javascript">

function getQueryString(){
console.log("Returning getQueryString");
return "<%=renderRequest.getAttribute("queryString")%>";
}

</script>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="HelloWorld" width="500px" height="500px"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie"
value='<%=renderResponse.encodeURL(renderRequest.getContextPath()
+ "/FlashQueryString.swf")%>' />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/FlashQueryString.swf")%>"
quality="high" bgcolor="#869ca7" width="500px" height="500px"
name="HelloWorld" align="middle" play="true" loop="false"
quality="high" allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed> </object>


Also i have getQueryString function that returns the query string set by the Portlet code as request attribute.

My Flex code is very simple

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="init()">
<fx:Script>
<![CDATA[
public function init():void{
if(ExternalInterface.available){
var queryString = ExternalInterface.call("getQueryString");
queryStringText.text = queryString;
}
}

]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel x="5" y="10" width="284" height="172" title="Query String Demo">
<s:TextArea x="10" y="44" width="220" height="54" id="queryStringText" />
<s:Label x="10" y="10" text="Query String" width="167" height="30"/>
</s:Panel>
</s:Application>


In the creationComplete() method of the Flex code i am calling getQueryString JavaScript method and setting value returned by it inside the text area for display

Getting Query String of portal URL from inside the portlet

Recently i had a requirement in which i wanted to send email to users with URL of portal server with some query parameter and when the user clicks on the link the portal page opens us and portlet read the query string in the URL to execute some business logic, so i built this sample portlet using technique described in Accessing underlying HttpServletRequest from PortletRequest in WebSphere Portal Server blog entry. You can download the sample code from here

First i did create a QueryStringPortlet portlet like this


public class QueryStringPortlet extends GenericPortlet{
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering QueryStringPortlet.doView()");
response.setContentType("text/html");
HttpServletRequest httpServletRequest = getHttpServletRequest(request);
String queryString = httpServletRequest.getQueryString();

System.out.println("Value of Query String " + queryString);
request.setAttribute("queryString",queryString);
getPortletContext().getRequestDispatcher("/query.jsp").include(request, response);
System.out.println("Exiting QueryStringPortlet.doView()");
}

private HttpServletRequest getHttpServletRequest(PortletRequest request){
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
while(httpServletRequest instanceof HttpServletRequestWrapper){
HttpServletRequestWrapper httpServletRequestWrapper =
(HttpServletRequestWrapper)httpServletRequest;
System.out.println("HttpServletRequestWrapper " + httpServletRequestWrapper);
httpServletRequest = (HttpServletRequest)httpServletRequestWrapper.getRequest();
}
return httpServletRequest;
}
}


As you can see, the doView() method is quite simple, all that it does is use getHttpServletRequest() method to get underlying HttpServletRequest object from the PortletRequest and then calls its httpServletRequest.getQueryString() method to get the query String. Once i have the query string i am setting it in the request object and forwarding control to JSP for rendering output.

After creating this portlet, i did add it to a page and created a URl mapping to map /querystring url to the page containing portlet, when i go to the /querystring page and some query string to it i see output like this


Accessing underlying HttpServletRequest from PortletRequest in WebSphere Portal Server

I wanted to figure out if i can access HttpServletRequest object that was passed to the portal server inside the Portlet, and it seems that i can do that using a method like this.

Note:This code is tested only in WebSphere Portal and i am not sure if it will work in the same way in any other standard compliant Portlet Container.


private HttpServletRequest getHttpServletRequest(PortletRequest request){
HttpServletRequest httpServletRequest = (HttpServletRequest)request;
while(httpServletRequest instanceof HttpServletRequestWrapper){
HttpServletRequestWrapper httpServletRequestWrapper =
(HttpServletRequestWrapper)httpServletRequest;
System.out.println("HttpServletRequestWrapper " + httpServletRequestWrapper);
httpServletRequest = (HttpServletRequest)httpServletRequestWrapper.getRequest();
}
return httpServletRequest;
}


The getHttpServletRequest() method takes PortletRequest method and first casts it into the HttpServletRequest object and then checks if its object of HttpServletRequestWrapper type if yes tries to get the wrapped object by calling its getRequest() method, it does this iteratively until it finds the HttpServletRequest object that is not instanceof HttpServletRequestWrapper


[5/9/10 15:48:20:960 PDT] 00000069 SystemOut O HttpServletRequestWrapper com.ibm.ws.portletcontainer.core.impl.RenderRequestImpl@302a302a wrapping com.ibm.wps.engine.PortalRequestWrapper@4be84be8 wrapping com.ibm.wps.engine.ExtendedLocaleRequest@4bbc4bbc wrapping <?xml version="1.0" encoding="UTF-8"?>
<com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper class="com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper">
<contextPath>/wpcert</contextPath>
<servletPath>/mydemo</servletPath>
<parent class="com.ibm.ws.webcontainer.srt.SRTServletRequest">com.ibm.ws.webcontainer.srt.SRTServletRequest@5d765d76</parent>
</com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper>

[5/9/10 15:48:20:961 PDT] 00000069 SystemOut O HttpServletRequestWrapper com.ibm.wps.engine.PortalRequestWrapper@4be84be8 wrapping com.ibm.wps.engine.ExtendedLocaleRequest@4bbc4bbc wrapping <?xml version="1.0" encoding="UTF-8"?>
<com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper class="com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper">
<contextPath>/wpcert</contextPath>
<servletPath>/mydemo</servletPath>
<parent class="com.ibm.ws.webcontainer.srt.SRTServletRequest">com.ibm.ws.webcontainer.srt.SRTServletRequest@5d765d76</parent>
</com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper>

[5/9/10 15:48:20:961 PDT] 00000069 SystemOut O HttpServletRequestWrapper com.ibm.wps.engine.ExtendedLocaleRequest@4bbc4bbc wrapping <?xml version="1.0" encoding="UTF-8"?>
<com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper class="com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper">
<contextPath>/wpcert</contextPath>
<servletPath>/mydemo</servletPath>
<parent class="com.ibm.ws.webcontainer.srt.SRTServletRequest">com.ibm.ws.webcontainer.srt.SRTServletRequest@5d765d76</parent>
</com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper>

[5/9/10 15:48:20:961 PDT] 00000069 SystemOut O HttpServletRequestWrapper <?xml version="1.0" encoding="UTF-8"?>
<com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper class="com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper">
<contextPath>/wpcert</contextPath>
<servletPath>/mydemo</servletPath>
<parent class="com.ibm.ws.webcontainer.srt.SRTServletRequest">com.ibm.ws.webcontainer.srt.SRTServletRequest@5d765d76</parent>
</com.ibm.wps.mappingurl.impl.MappingURLRequestWrapper>


This is output that i see when i call getHttpServletRequest() method from the doView() method of my sample portlet

Supporting Multiple modes with Spring Portlet MVC Framework

In the HelloWorld Spring Portlet MVC Framework 3.0.1 entry i did build a simple HelloWorld Spring portlet which supports only VIEW mode.

Today i built a MultipleModesPortlet to demonstrate how you can support more than one mode using Spring MVC Framework. You can download the sample code from here

The MutlipleModesPortlet, support three modes VIEW, EDIT and HELP, It has one controller class for every mode. Ex ViewController class will handle every request for VIEW mode, the EditController class will handle every request for EDIT mode and HelpController class will handle every request for help mode. Only thing that Controller does is forward control to a JSP for rendering markup. The ViewController forwards control to view.jsp and similarly the other controller forward control to corresponding JSP.

This is how my ViewController.java looks like

public class ViewController extends AbstractController{
protected ModelAndView handleRenderRequestInternal(RenderRequest request,
RenderResponse response) throws Exception {
System.out.println("Entering ViewController.handleRenderRequest()");
ModelAndView modelAndView = new ModelAndView("view");
System.out.println("Exiting ViewController.handleRenderRequest()");
return modelAndView;
}
}


As you can see the ViewController class overrides handleRenderRequestInternal() method which gets call every time user tries to access the portlet in VIEW mode. Inside the handleRenderRequestInternal() method i am creating and returning ModelAndView("view") object. Which is equivalent to forwarding control to JSP for generating markup.

This is how my view.jsp looks like

<%@page language="java" contentType="text/html; %>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<portlet:defineObjects />
<h1>Hello from view.jsp</h1>

As you can see this JSP is generating static text.

Now the more important part is how to configure Spring Portlet MVC framework so that different controllers get called for different modes and the answer is that configuration goes in MultipleModes-portlet.xml like this

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

<bean id="viewController"
class="com.webspherenotes.mvc.spring.action.ViewController" />
<bean id="editController"
class="com.webspherenotes.mvc.spring.action.EditController" />
<bean id="helpController"
class="com.webspherenotes.mvc.spring.action.HelpController" />
<bean id="portletModeHandlerMapping"
class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
<property name="order" value="1" />
<property name="portletModeMap">
<map>
<entry key="view">
<ref bean="viewController" />
</entry>
<entry key="edit">
<ref bean="editController" />
</entry>
<entry key="help">
<ref bean="helpController" />
</entry>
</map>

</property>
</bean>

<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass">
<value>org.springframework.web.servlet.view.JstlView</value>
</property>
<property name="prefix">
<value>/WEB-INF/jsp/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>


As you can see first i have created three bean definitions one for each Controller, this is the Controller class for com.webspherenotes.mvc.spring.action.EditController

Then the important part is portletModeHandlerMapping which has portletModeMap map that is used for mapping a Controller class to the mode. I am mapping view mode to viewController and edit mode to editController,..

Flex and WebServices Portlet

If you follow this blog regularly you might have noticed that i am experimenting with how to use Flex in Portlet, which seems to be getting popular option. I started by creating simple Contact table in the database and then demonstrated how you can use Flex for adding and displaying records in the table. So far i have demonstrated how to use


In this last part i am going to demonstrate how you can use the Web Service in the Portlet from Flex application. The basic idea is that the Portlet will return HTML that loads Flex object from the doView() method but once that is done, the Flex will talk directly to the Web Service which is part of Same Portlet .war file directly without going through portlet



You can download the sample code for this blog from here



First i did create a simple WebServicesContactPortlet portlet like this

public class WebServicesContactPortlet extends javax.portlet.GenericPortlet {
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
System.out.println("Entering WebServicesContactPortlet.doView()");
response.setContentType(request.getResponseContentType());
getPortletContext().getRequestDispatcher("/index.jsp").include(request, response);

}
}


In this portlet i am forwarding control to index.jsp for generating markup of the view mode. The index.jsp includes WSDataExchange.swf, this is how my Flex source looks like

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="initLogging()">
<fx:Script>
<![CDATA[
import com.webspherenotes.flex.Contact;
import mx.controls.Alert;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.soap.WebService;
import mx.utils.ObjectUtil;
private function initLogging():void {
trace("Entering initLogging");
var logTarget:TraceTarget = new TraceTarget();
logTarget.level = LogEventLevel.ALL;
contactList.getContactList.send();
trace("Exiting initLogging");
}
public function getContactList_result(event:ResultEvent):void{
trace("Inside getContactList_result");
dgEmployees.dataProvider = event.result;
trace("ContactList result" + event.result);
}
public function faultHandler(event:FaultEvent):void{
trace("Inside getContactList_fault");
}
public function addContact():void{
trace("Entering addContact")
var mycontact:Contact = new Contact();
mycontact.firstName =txtFirstName.text;
mycontact.lastName = txtLastName.text;
mycontact.email = txtEmail.text;
contactList.insertContact.send(mycontact);
contactList.getContactList.send();
}
public function insertContact_result(event:ResultEvent):void{
trace("Entering insertContact_result");
}
]]>
</fx:Script>
<fx:Declarations>
<mx:WebService id="contactList"
wsdl="http://localhost:10040/wpcert/wscontactportlet/services/ContactDAOImpl/wsdl/ContactDAOImpl.wsdl">
<mx:operation name="getContactList"
resultFormat="object"
result="getContactList_result(event);"
fault="faultHandler(event);" />
<mx:operation name="insertContact"
resultFormat="object"
result="insertContact_result(event);"
fault="faultHandler(event);" />
</mx:WebService>

</fx:Declarations>
<mx:Panel x="0" y="0" width="500" height="410" layout="absolute"
title="Simple WebService Example">
<mx:DataGrid x="10" y="174" width="460" enabled="true" editable="false"
id="dgEmployees">
<mx:columns>
<mx:DataGridColumn headerText="First Name" dataField="firstName"/>
<mx:DataGridColumn headerText="Last Name" dataField="lastName"/>
<mx:DataGridColumn headerText="Email" dataField="email"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="190" y="121" label="Add Employee" id="getPerson" click="addContact()" />
<mx:Label x="110" y="12" text="First Name"/>
<mx:TextInput x="189" y="10" id="txtFirstName" />
<mx:Label x="110" y="50" text="Last Name"/>
<mx:TextInput x="189" y="48" id="txtLastName" />
<mx:Label x="110" y="84" text="E-mail"/>
<mx:TextInput x="189" y="82" id="txtEmail" />
<mx:Label x="10" y="148" text="Employees:"/>
</mx:Panel>
</s:Application>


The mx:WebService mxml element is pointing to the ContactDAOImpl web services which is part of my portlet and the two mx:operation declare that i want to use the getContactList and insertContact operation of ContactDaoImpl web service.

On the load of the swf file it calls initLogging() and in that method i am calling contactList.getContactList.send(), this results in getContactList operation of contactList service being called and once the results of the web service is available i get control in the getContactList_result method and i am using that method to assign results of websevice as dgEmployees.dataProvider

When it comes to calling web service with complex object first i have to create object of Contact which is defined as ActionScript class like this in my code

package com.webspherenotes.flex
{
[Bindable]
[RemoteClass(alias="com.webspherenotes.flex.dao.Contact")]
public class Contact
{
private var _firstName:String;
private var _lastName:String;
private var _email:String;
public function Contact()
{
}
public function get email():String
{
return _email;
}
public function set email(value:String):void
{
_email = value;
}
public function get lastName():String
{
return _lastName;
}
public function set lastName(value:String):void
{
_lastName = value;
}
public function get firstName():String
{
return _firstName;
}
public function set firstName(value:String):void
{
_firstName = value;
}
}
}


When i call contactList.insertContact.send(mycontact);, the ActionScript takes care of converting the object of Contact class into XML and passing it as argument to insertContact

For generating WebService i did copy my ContactDaoImpl in my portlet, and used RAD's generate Web Service feature to generate a web service to expose that Java Object. This is how my WebService Contact Portlet looks like