Wednesday, February 3, 2010

Custom Portlet Scope for Spring, JSF, RichFaces portlet Applications

It is all to usual scenario. Create a Portlet, create a Spring bean with the scope="session" or scope="globalSession" and hope that everything works just fine. And it does, until you don't have the scenario where the user creates two separate instance of the same portlet definition.

In that case, all you get is two portlets which display the same informations. Why? Because both of the portlet instances are getting their data from the same Backing Bean instance.

One would wonder, should one use the Spring DispatcherPortlet. If yes, how do I put all that together with JSF, RichFaces etc. At least I did not manage to find any tutorial or example how to put all that technologies together.

So, are we using the right technologies? Still the Answear is most probably yes!

Looking for a soulution, I came accross the information, that one can define his own scope for the Spring Beans.

So I decidet to create own custom scope that saves the Spring Beans per portlet Instance. In other words, each Spring Bean Instance is saved in the PortletSession.PORTLET_SCOPE of the session.

Here is the Custom Scope definition.


public class PortletSessionScope extends AbstractRequestAttributesScope {

private final int scope;


public PortletSessionScope() {
this.scope = PortletSession.PORTLET_SCOPE;
}

@Override
protected int getScope() {
return this.scope;
}

public String getConversationId() {
String sessionId = RequestContextHolder.currentRequestAttributes().getSessionId();
return sessionId;
}


@Override
public Object get(String name, ObjectFactory objectFactory) {
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
Object mutex = requestAttributes.getSessionMutex();
synchronized (mutex) {
ExternalContext external = FacesContext.getCurrentInstance().getExternalContext();
Object scopedObject = null;
Object session = null;
if (null != external) {
session = external.getSession(false);
if (null != session && session instanceof PortletSession) {

scopedObject = ((PortletSession) session).getAttribute(name, PortletSession.PORTLET_SCOPE);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
((PortletSession) session).setAttribute(name, scopedObject, PortletSession.PORTLET_SCOPE);
}
else if (null != session && session instanceof ServletSessionWrapper) {

scopedObject = ((ServletSessionWrapper) session).getAttribute(name);
if (scopedObject == null) {
scopedObject = objectFactory.getObject();
((ServletSessionWrapper) session).setAttribute(name, scopedObject);
}
}
}

return scopedObject;
}
}

@Override
public Object remove(String name) {

Object mutex = RequestContextHolder.currentRequestAttributes().getSessionMutex();
synchronized (mutex) {
Object scopedObject = super.remove(name);
return scopedObject;
}
}
}
So now that you have the scoped bean, all it takes is to make it known to Spring. That is streight process.

In your applicationContext.xml, where all the beans are ceclared, do the following:














So, with that done, all it takes to get Spring Bean in PorltetSession.PORTLET_SCOPE is a deffinition of a Bean with the above scope, something like this:






That was it. Hope it works for you!

Wednesday, September 23, 2009

RichFaces Table with DataModel

Recently I needed to get the selected Row Object of my RichFaces Data Table in to a backing bean, so that I can further manipulate it.

Before that, I was using Array List to feed my Data Table. Somewhere on the way, I picked up that one can use the


import javax.faces.model.ArrayDataModel;
import javax.faces.model.DataModel;


from JSF. Let us say, that you have a Data Table, where you have a Data Object similar to this one:


public class DataObject{

private String fileName;
private String fileMime;
public DataObject(String fileName, String fileMime){
this.fileName=fileName;
this.fileMime=fileMime;
}
// getter and setter
// exist but are omitted for this example.
}


This Data Object can come from various sources, such as data base or services, or your business layer.

It is nice to have an icon displayed in the Data Table instead of the row Mime type, such as plain/text or something similar.

Let us assume, you have a set of application icons.

Now you write your data table in the XHTML File, and it looks similar to this:


















As you can see, the name of the file is taken directly from the table Data Model, while for the file type, we call a backing bean method to handle the mime type.

The real question is, how do we know which index of the array do we have at rendering time, so that we can calculate the image URL for the certain mime type.

The Backing bean would look similar to this:


public class MyBean{

private List dataModelList;
private DataModel dataModel;

public void init(){
// populate simple Array List
// with Data Objects.
dataModelList = new ArrayList();
dataModelList.add(new DataObject("first","plain/text"));
dataModelList.add(new DataObject("second","text/html"));

// fill the Data Model
dataModel = new ArrayDataModel(dataModelList);
}
/**
* The method that returns an string representation of
* of Image URL for the mime type of the file.
*/
public String getMimeIcon(){

if(null == dataModel){
return null;
}

if(dataModel.isRowAvailable()){
DataObject rowDataObject =
(DataObject) dataModel.getRowData();
return calculateMimeType(rowDataObject.getFileMime());
}
return null;
}
//getter and setter for the Data Model omitted here
// but exist in the real source.
}


As you can see, in the backing bean, the getter method getMimeIcon(); we look up if the data model row is available.

If so, the getRowData(); of the Data Model will return exactly the the Object for the row referenced by the Tag at iteration (render) time.

In this case, we can have as many mime typed object in the Data Model Object as we want. We can be certain of it, that each of them get their right mime type icon.

Tuesday, August 25, 2009

IPC issue in WebSphere 6.1

Inter Portlet Comunication (IPC) is the hot spot in Portal environment. I already had some experience with it and described it here: IPC with JSR 286.

Everyone would probably think as I thought, that this should work in WebSphere Portal 6.1.

And it does. BUT! There is one additional requirement for having this to work under WPS 6.1.

After deploying your Portlets in the WPS you will have to go to the Administration Tab of WPS.

Than on the left side click the Manage Pages.
In the newly opened page, you will see a Table with only one column. Click on ContentRoot.

After that you will have to find your own Page-Name, which corresponds to the the Tab-Name where you run your Portlets.

When done, on the far right you will see bunch of icons. Click pencil like icon (it also displays the name EDIT PAGE LAYOUT when going over with your mouse).

The Page Customizer will open. Four Tabs are available:

  • Content
  • Appearance
  • Locks
  • Wires

In the Content Tab, you add all the Portlets you want to run here on this page (your newly developed Portlets with IPC).

After doing, click the Wires Tab. WPS has already read your portlet.xml file. You will see a table with the following columns:

  • Source portlet - The Event Publishing Portlet
  • Sending - The Publishing Event name space and name
  • Target page - leave it as it is. Here you can define the Page if your target Portlet is on another page. If on the same page, leave it as it is.
  • Switch page - I don't really get it what this has to do with all of this here (but hey)
  • Target portlet - The Portlet that has to consume your Published Event
  • Receiving - The name space and name of your Published Event.
  • Wire Type - leave it to Public

Don't forget to press the tiny + button on the end. This has to be repeated for each IPC Event of your Portlets.

When done, press the Done Button.

Now you can go to your Page Tab and test your IPC Eventing.

Hope it works for you too.