Spring Framework 3.0.1 has support for Portlet Specification 2.0

Yesterday i was talking with my friend Sanjay and he said that Spring Framework Release 3.0.1 has Support for Portlet Specification 2.0. Today i looked at the documentation of Dispatcher, i can see that it has method like serveResource(), doEventService()

Creating application specific log in the Flex program

You can create application specific log in your flex application like this. In my case i am initializing myLogger in the initLogger() method at the time of document creation and once the logger is initialized we can write something at debug level by calling myLogger.debug() method.

Similar to debug there are methods to indicate log statement at different levels, same as that of log4j.


<?xml version="1.0"?>
<!-- logging/ButtonLifeCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete='initLogging()'>
<mx:Script><![CDATA[
import mx.controls.Alert;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private var myLogger:ILogger;
private function initLogging():void {
var logTarget:TraceTarget = new TraceTarget();
logTarget.filters=["MyCustomClass"];
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
myLogger = Log.getLogger("MyCustomClass");
}


private function traceClick():void {
myLogger.debug("Entering traceClick");
useHttpService("http://www.google.com");
myLogger.debug("Exiting traceClick");
}

private var service:HTTPService
public function useHttpService(url:String):void {
myLogger.debug("Entering useHttpService");
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "GET";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
myLogger.debug("Entering useHttpService");
}
public function httpResult(event:ResultEvent):void {
myLogger.debug("Entering httpResult");
var result:Object = event.result;
Alert.show(event.result.toString());
myLogger.debug("Entering httpResult");
}
public function httpFault(event:FaultEvent):void {
myLogger.debug("Entering httpFault");
var faultstring:String = event.fault.faultString;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
myLogger.debug("Entering httpFault");
}
]]></mx:Script>
<mx:Button id="b1" label="Click Me" click="traceClick()" />
</mx:Application>

Enabling log Flex applicationEnable log for HTTPService in Flex application

When i started with Flex development, i was trying to make HTTP call to the portlet and i was not able to get any response so i did add this code to my Flex program to enable the log so that i can see what was going on with the HTTPService.

In order to use the Logging you will have to Enable trace in the Flex program


<?xml version="1.0"?>
<!-- logging/ButtonLifeCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete='initLogging()' >
<mx:Script><![CDATA[
import mx.controls.Alert;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private function initLogging():void {
var logTarget:TraceTarget = new TraceTarget();
logTarget.filters=["mx.rpc.*","mx.messaging.*"];
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
}

private function traceClick():void {
useHttpService("http://www.google.com");
}

private var service:HTTPService
public function useHttpService(url:String):void {
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "GET";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
}
public function httpResult(event:ResultEvent):void {
var result:Object = event.result;
Alert.show(event.result.toString());
}
public function httpFault(event:FaultEvent):void {
var faultstring:String = event.fault.faultString;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
}
]]></mx:Script>
<mx:Button id="b1" label="Click Me" click="traceClick()" />
</mx:Application>


The log is disabled by default in Flex so first i had to create initLogging() function to enable trace and then call it from createComplete() so that the log for HTTPService gets enabled. After that i could see this log in flashlog.txt when i tried making call to www.google.com from Flex application

'7671B99A-ED63-A113-A196-E28CF5762B74' producer set destination to 'DefaultHTTP'.
'direct_http_channel' channel endpoint set to http:
'7671B99A-ED63-A113-A196-E28CF5762B74' producer sending message 'D672CE47-357B-884E-07D7-E28CF5D40D82'
'direct_http_channel' channel sending message:
(mx.messaging.messages::HTTPRequestMessage)#0
body = (Object)#1
clientId = (null)
contentType = "application/x-www-form-urlencoded"
destination = "DefaultHTTP"
headers = (Object)#2
httpHeaders = (Object)#3
messageId = "D672CE47-357B-884E-07D7-E28CF5D40D82"
method = "GET"
recordHeaders = false
timestamp = 0
timeToLive = 0
url = "http://www.google.com"
'7671B99A-ED63-A113-A196-E28CF5762B74' producer connected.
'7671B99A-ED63-A113-A196-E28CF5762B74' producer acknowledge of 'D672CE47-357B-884E-07D7-E28CF5D40D82'.
Decoding HTTPService response
Processing HTTPService response message:
(mx.messaging.messages::AcknowledgeMessage)#0
body = "<!doctype html><html onmousemove="google&&google.fade&&google.fade(event)"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Google</title><script>window.google={kEI:"upR9S5bhE4_MowTPsPWXCg",kEXPI:"17259,21965,23394,23807",kCSI:{e:"17259,21965,23394,23807",ei:"upR9S5bhE4_MowTPsPWXCg",expi:"17259,21965,23394,23807"},pageState:"#",kHL:"en",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||"/gen_204?atyp=i&ct="+b+"&cad="+d+"&zx="+google.time();a.src=c;e.li=f+1},lc:[],li:0,j:{en:1,l:function(){},e:function(){},b:location.hash&&location.hash!="#",pl:[],mc:0,sc:0.5},Toolbelt:{}};(function(){for(var d=0,c;c=["ad","bc","p","pa","zd","ac","pc","pah","ph","sa","xx","zc","zz"][d++];)(function(a){google.j[a]=function(){google.j.pl.push([a,arguments])}})(c)})();
window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{window.google.pt=window.gtbExternal&&window.gtbExternal.pageT();}catch(u){}window.google.jsrt_kill=1;
"
clientId = "DirectHTTPChannel0"
correlationId = "D672CE47-357B-884E-07D7-E28CF5D40D82"
destination = ""
headers = (Object)#1
DSStatusCode = 200
messageId = "3CAC4096-54F6-BF7C-EEB9-E28CF855D638"
timestamp = 0
timeToLive = 0
Warning: Ignoring 'secure' attribute in policy file from http://ad.doubleclick.net/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
Warning: Ignoring 'secure' attribute in policy file from http://ad.doubleclick.net/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i3.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i4.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i2.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain video-stats.video.google.com does not explicitly specify a meta-policy, but Content-Type of policy file http://video-stats.video.google.com/crossdomain.xml is 'text/x-cross-domain-policy'. Applying meta-policy 'by-content-type'.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain video-stats.video.google.com does not explicitly specify a meta-policy, but Content-Type of policy file http://video-stats.video.google.com/crossdomain.xml is 'text/x-cross-domain-policy'. Applying meta-policy 'by-content-type'.

Flashbug for Flex developer

FlashBug is a very nice and useful extension of FireBug, if your serious Flash Developer



It lets you look at the flashlog.txt, policylog.txt in the console and provides ability to cleanup the log

Please note that you will have to Enable trace in the Flex program before you can use Flashbug

Enable trace in the Flex program

By default the Tracing is disabled in the flex player but you can enable it by going to C:\Documents and Settings\sunpatil\mm.cfg file and modifying value of TraceOutputFileEnabled to 1 instead of 0. Then restart your browser and execute your flex program again.


#flashlog
# Beginning with the Flash Player 9 Update, Flash Player ignores the TraceOutputFileName property.
# On Macintosh OS X, you should use colons to separate directories in the TraceOutputFileName path rather than slashes.
TraceOutputFileName=C:\Documents and Settings\<username>\Application Data\Macromedia\Flash Player\Logs\flashlog.txt # Set TraceOutputFileName to override the default name and location of the log file

ErrorReportingEnable=1 # Enables the logging of error messages. 0/1
TraceOutputFileEnable=1 # Enables trace logging. 0/1
MaxWarnings=100 # Sets the number of warnings to log before stopping.

#policyfiles
PolicyFileLog=1 # Enables policy file logging
PolicyFileLogAppend=1 # Optional; do not clear log at startup


Now open the C:\Documents and Settings\<username>\Application Data\Macromedia\Flash Player\Logs\flashlog.txt file in text editor and you should see the trace generated by your flex program. Other option is to use FlashBug which is a plugin in firebug

Global trace in your Adobe Flex program

Ability to trace message is very important in building any complex program. You can use the debugger version of Flash Player to capture output from the global trace() method and write that output to the client log file. You can use trace() statements in any ActionScript or MXML file in your application. Because it is a global function, you are not required to import any ActionScript classes packages to use the trace() method.


<?xml version="1.0"?>
<!-- logging/ButtonLifeCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete='trace(employees)'>
<mx:Script><![CDATA[
private function traceClick():void {
trace("Entering traceClick");
trace("Exiting traceClick");
}
]]></mx:Script>
<mx:XMLList id="employees">
<employee>
<name>Christina Coenraets</name>
<phone>555-219-2270</phone>
<email>ccoenraets@fictitious.com</email>
<active>true</active>
</employee>
<employee>
<name>Joanne Wall</name>
<phone>555-219-2012</phone>
<email>jwall@fictitious.com</email>
<active>true</active>
</employee>
</mx:XMLList>
<mx:Button id="b1" label="Click Me" click="traceClick()" />
</mx:Application>


You can call trace() method from either the ActionScript or from MXML with either object or String as argument and that message will get traced to the flashlog.txt, if trace is enabled like this



Christina Coenraets
555-219-2270
ccoenraets@fictitious.com
true


Joanne Wall
555-219-2012
jwall@fictitious.com
true

Entering traceClick
Exiting traceClick

Debugger version of flash player

The debugger version of Flash player can play the swf files similar to the flash player but in addition to that it lets you do following things


  • Output statements and application errors to the debugger version of the Flash Player local log file by using the trace() method.

  • Write data services log messages to the local log file of the debugger version of Flash Player.

  • View run-time errors (RTEs).

  • Use the fdb command-line debugger.

  • Use the Flex Builder debugging tool.

  • Use the Flex Builder profiling tool.



If you have the Flex builder installed on your machine then you can get the Flash player debugger version from AdobeFlashBuilder\player\<osname> directory or you can download it from http://www.adobe.com/support/flashplayer/downloads.html.

Once installed you check if your using the flash debugger by right clicking on your flash player, it should show a context menu for Debugger like this

Handling WindowState change on client side

The Infocenter for WebSphere Portal has Changing portlet mode and window state on the client side document that describes how you can handle the portlet mode change on the client side

I tried creating a JavaScript function like this

function doWindowState( windowState, div ){
console.log("Entering namespace specific doWindowState ");
console.log("Exiting namespace specific doWindowState ");
return true;
}


but it does not get called when i click on either Maximize or Minimize button but then i tried using the same trick that i used for doPortletMode() blog and created a JavaScript code like this

function PC_<%=portletWindowID%>_doWindowState( windowState, div ){
console.log("Entering PC_<%=portletWindowID%>_ specific doWindowState ");
console.log("Window State " + windowState);
console.log("Window State " + div);
div.innerHTML="Content set on the client side"
console.log("Exiting PC_<%=portletWindowID%>_ specific doWindowState ");
return true;
}


The function gets control when i click on either minimize or maximize button but when i set the div.innerHTML it throws some wiered JavaScript exceptions like this

Using doPortletMode to handle portlet mode change on client side

In client-side aggregation, you can provide an event handler for changes of portlet mode and portlet window state. This handler gets called when a mode change or a window state change is triggered.

The Infocenter for WebSphere Portal has Changing portlet mode and window state on the client side document that describes how you can handle the portlet mode change on the client side

Note: This function is currently only supported in the portal CSA theme and the CSA skin. You can adapt the CSA theme and skin to write your own custom themes and skins to support this feature.

The return value of your handler determines whether or not the default action is executed:

  • A return value of true allows execution of the default action, in this case the portlet mode or window state change.

  • A return value of false cancels the default action.



This allows the portlet to handle these changes entirely on the client, with no server interaction.

I tried adding JavaScript function as described in the Infocenter in my portlet but that function never gets called.

function doPortletMode( portletMode, div ){
console.log("Entering namespace specific doPortletMode ");
var retVal = true;
if ( portletMode == ibm.portal.portlet.PortletMode.EDIT) {
div.innerHTML = "

Edit Mode from client side

";
retVal = false;
}
console.log("Exiting namespace specific doPortletMode ");
return retVal;
}


THen i looked the ibmCSA.js to find out what is it looking for and it appears that it is looking for PC_<%=portletWindowID%>_doPortletMode function name so i made change in my portlet to create function like this


function PC_<%=portletWindowID%>_doPortletMode( portletMode, div ){
console.log("Entering PC_WindowIdspecific doPortletMode ");
var retVal = true;
if ( portletMode == ibm.portal.portlet.PortletMode.EDIT) {
div.innerHTML = "

Edit Mode from client side

";
retVal = false;
}
console.log("Exiting PC_WindowIdspecific doPortletMode ");
return retVal;
}


After this change i could see that function was getting called when i clicked on personalized but the div which i am changing in my code is hidden so even though the setting of innerHTML works user does not see anything.

I made change to set div.style.display=""; after setting innerHTML and now i can see that the innerHTML that i am setting gets displayed to the user but problem is when is that when i exit back to view mode it does not hide the div

Getting Edit or Help mode markup from the Flex portlet

I made changes in the How to make action or render request from the Adobe Flex so that it makes request to get the markup for Edit and Help mode from the Flex. These are the changes in the source code


public class SPRInFlexPortlet extends javax.portlet.GenericPortlet {
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
// Set the MIME type for the render response
response.setContentType(request.getResponseContentType());
System.out.println("Entering SPRInFlexPortlet.doView()");
if(request.getParameter("caller") == null){
System.out.println("Request from portal, not flex");
SPRUtil sprUtil = new SPRUtil();
String editModeUrl = sprUtil.getPortletEditModeUrl(request, response);
String helpModeUrl = sprUtil.getPortletHelpModeUrl(request, response);
request.setAttribute("editModeUrl", editModeUrl);
request.setAttribute("helpModeUrl", helpModeUrl);

getPortletContext().getRequestDispatcher("/sprinflex.jsp").include(request, response);
return;
}
PrintWriter out = response.getWriter();
out.println("Listing out parameters in the SPRFlexPortlet.doView()");
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()){
String paramName = paramNames.nextElement();
System.out.println(paramName +" " + request.getParameter(paramName));
out.println(paramName +" " + request.getParameter(paramName)+" ");
}
System.out.println("Got request for the first time");
}
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, java.io.IOException {
System.out.println("Entering SPRInFlexPortlet.processAction");
Enumeration paramNames = request.getParameterNames();
while(paramNames.hasMoreElements()){
String paramName = paramNames.nextElement();
System.out.println(paramName +" " + request.getParameter(paramName));
response.setRenderParameter(paramName, request.getParameter(paramName));
}
response.setRenderParameter("requestType", "action");
System.out.println("Exiting SPRInFlexPortlet.processAction");
}
protected void doEdit(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering SPRInFlexPortlet.doEdit");
response.setContentType(request.getResponseContentType());
response.getWriter().println("Returning response from SPRInFlexPortlet.doEdit()");
System.out.println("Exiting SPRInFlexPortlet.doEdit");
}
protected void doHelp(RenderRequest request, RenderResponse response)

throws PortletException, IOException {
System.out.println("Entering SPRInFlexPortlet.doHelp");
response.setContentType(request.getResponseContentType());
response.getWriter().println("Returning response from SPRInFlexPortlet.doHelp()");
System.out.println("Exiting SPRInFlexPortlet.doHelp");
}

}



<%@page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portlet"%>
<%@taglib uri="http://java.sun.com/portlet" prefix="portletx"%>
<portlet:defineObjects />
<script type="text/javascript">
function getEditModeUrl(){
console.log("Returning renderUrl");
return "<%=renderRequest.getAttribute("editModeUrl")%>";
}
function getHelpModeUrl(){
console.log("Returning processActionUrl");
return "<%=renderRequest.getAttribute("helpModeUrl")%>";
}

</script>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
width="750" height="500" height="100%"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie"
value='<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/HelloWorld.swf") %>' />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/HelloFlex.swf") %>"
quality="high" bgcolor="#869ca7"
width="750" height="500" 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>


<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
width="100%" height="100%" >
<mx:Panel id="pnlMain" layout="absolute" title="Serve Resource Example">
<mx:Button label="Edit Mode request" y= "11" id="resourceUrl"
click="makeEditModeCall()" x="351"/>
<mx:Button label="Help Mode request" y= "54" id="resourceUrl0"
click="makeHelpModeCall()" x="351"/>
<mx:TextArea x="7" y="135" width="493" height="198" id="displayText"/>
<mx:TextInput x="142" y="10" id="httpMethod" text="GET"/>
<mx:Label x="10" y="12" text="Http Method" width="124"/>
<mx:Label x="10" y="54" text="Parameters"/>
<mx:TextInput x="142" y="54" id="httpParam"/>
<mx:Label x="10" y="106" text="Portlet Response"/>
</mx:Panel>
<mx:Script>
<![CDATA[
import flash.external.*;
import mx.controls.Alert;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
//Event handler for handling button click
public function makeHelpModeCall():void
{
if (ExternalInterface.available) {
var portletUrl:String = ExternalInterface.call("getHelpModeUrl");
useHttpService(portletUrl);
} else
displayText.text = "Unable to call JavaScript";
}
public function makeEditModeCall():void
{
if (ExternalInterface.available) {
var portletUrl:String = ExternalInterface.call("getEditModeUrl");
useHttpService(portletUrl);
} else
displayText.text = "Unable to call JavaScript";
}

//This method is used for making a URL call
private var service:HTTPService
public function useHttpService(url:String):void {
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = httpMethod.text;
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
}
//This callback gets called in case if the http response is returned
public function httpResult(event:ResultEvent):void {
var result:Object = event.result;
displayText.text = event.result.toString();
}
//This call back gets called in case of error in http request
public function httpFault(event:FaultEvent):void {
var faultstring:String = event.fault.faultString;
displayText.text = event.fault.faultDetail;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
}
]]>
</mx:Script>
</mx:Application>