Youtube Portlet - Adding videos to your portal
Not too long ago, we added a Video Portlet to the Portlet Repository project. This portlet application utilizes the REST API exposed by Youtube for it's functionality. You can find out more about the portlet on our brand new wiki site: Video Portlet documentation.
And here is a quick screenshot:
The user interface is a little primitive and I would like to blame it on my lack of UI skills ;-). I am still working on it (if you are interested in helping out, please leave a comment or send me an email). I am also trying to figure out what other functionality is worth adding
Posted at 12:53AM Feb 16, 2007 by Navaneeth Krishnan in Portlet |
Understanding Portlet 2.0 (JSR 286) - Part 2
In my previous blog entry (Part 1), I mentioned that one of the key limitations of the Portlet 1.0 spec was that it did not provide a mechanism for one portlet to "notify" another portlet that it's state has changed. Thankfully, Portlet 2.0 provides (not one but two!) mechanisms by which portlets can communicate with each other.
For the sake of illustration consider a portal page with two portlets : A user profile portlet (Profile portlet) which stores the personal details of the logged in user and a Weather portlet which shows the weekly weather forecast for a particular location. Our usecase is that when the user updates her profile address to a new location, the Weather portlet needs to show the weather forecast for that particular location.
In Portlet 1.0, developers are left with no choice but to use a shared memory space. When the first portlet is being acted upon , in this case the Profile Portlet is clicked, it stores the data that needs to be communicated into a shared memory space. When the portlet that needs to receive this data is being rendered, it is programmed to read the data from the same shared memory. Here is a quick illustration.
In processAction() of ProfilePortlet, data is written to shared memory:
During render() of WeatherPortlet, data is read from the shared memory:
So, what is this shared memory space ? Well, if you bundle these two portlet into a single portlet application (i.e a single war file sharing the same portlet.xml) there are two easy choices: The PortletSession and the PortletContext.
Here, the notion of sessions and context is very similar to (you could even say copied from :) the Servlet world. A PortletSession exists per user per portlet application (like HttpSession exists per user per web application) and a PortletContext is shared between all users and all portlets for a given portlet application (ServletContext is shared between all users and servlets in a web application). However, Portlets additionally possess a mechanism to conveniently namespace an attribute that is placed in the session. This mechanism is called "scoping". The scoping mechanism helps a portlet to easily differentiate between data that is used exclusively by itself (referred to as Portlet-scoped data) and data that is shared between it and other portlets in the application (referred to a Application-scoped data).
While both the PortletSession and PortletContext can be used to solve the interportlet communication problem, this scenario occurs most frequently in the context of a user accessing a portal. Hence it is typical to use the PortletSession.( And though PortletContext can be used when you want the data to be propagated to *all* users – there might be a better way of handling such a case).
The source code would look like this:
In processAction of ProfilePortlet :
portletSession.setAttribute("location", newLocation, PortletSession.APPLICATION_SCOPE);
In render of WeatherPortlet:
currentLocation = (String) portletSession.getAttribute("location",PortletSession.APPLICATION_SCOPE);
showWeatherForThisLocation(currentLocation);
There are a bunch of problems with this approach. Firstly, using the PortletSession (or PortletContext) is only possible when the portlets are packaged as a part of the same portlet application. For portlets that are part of different portlet applications, this won't work -since the sessions and contexts are different. Hence, in such cases, you need to resort to other standard communication mechanisms JMS (messaging), JNDI etc. And such solutions are far from tirvial and sometime becomes an overkill for the problem we are trying to address.
Secondly, the Weather Portlet is limited by the semantics of the portlet programming model, on how it can respond to the communicated data. This is because portlets are not allowed to change their states during a render()(as rendering is defined as idempotent). And the Weather Portlet is only rendered and never acted upon. Hence it will not be able to change it's window state, mode or preferences during the above interaction. This is seriously limiting.
Thirdly, there is no way for the Weather portlet to communicate back to the Profile portlet (or any other portlet), if at all it wants to. The above communication is one-time and unidirectional.
Finally, from a design perspective, this is probably not what a session (or context ) is meant to be used for. And this could lead to bad code. (As developers might develop the tendency to put all transient data into the HttpSession just because it is easier to share it between multiple portlets)
Portlet 2.0 introduces a full-fledged interportlet communication mechanism called Eventing. Eventing can be described as a loosely coupled, brokered means of communication between portlets. It is loosely coupled because portlets that send events need not have any compile-time or runtime dependency on the portlets that receive that event (or vice versa). It is brokered because the portal/portlet container acts as a conduit for these events.
The simplest way to understand eventing is to consider the portlet-container as an "event bus". Portlets that need to send notifications to other portlets publish events. Portlets that are interested in receiving notifications from others subscribe to events.
To illustrate eventing, let's take the same example as above and see how we would implement a Portlet 2.0 solution. First step, the user clicks on the Profile portlet and changes her location.This triggers a processAction() on the Profile portlet and the`portlet updates it's state.At the end of this processAction() phase, the portlet does something different. Instead of writing to a`shared memory, like the previous example, it requests the portlet-container to send a "location changed" event.
The next phase is called the eventing phase. This is when the portlet-container determines which other portlets needs to receive this event and routes it appropriately. In this case, we assume that the Weather portlet was configured to consume this event, hence the event sent to the Weather Portlet.
The next is the render phase. Notice that in this case, the portlet doesn't need to do anything special. It just needs to render itself, according to it's current state.
In the above illustration, it is pretty easy to notice that Portlet 2.0 has solved the problem by introducing a separate new lifecycle phase - the eventing phase. So our original lifecycle diagram can be modified to this now:
Eventing always occurs after processAction(). It also always occurs before the render(). And eventing can modify state (i.e it is a non-idempotent operation). This solves most of the shortcomings we noticed in the Portlet 1.0 implementation.
Since eventing does not rely on any shared memory space, even portlets from different portlet applications can communicate with each other. Also, since eventing is defined as a state-modifying operation, the portlet is free to make an any persistent change to it's state including changing it's mode or window state, storing user preferences or modifying a database backend. Changes to it's UI will be reflected in the rendering phase that follows.
Another interesting aspect is that the Weather Portlet is free to respond to the "location changed" event by sending it's own new event. And if the Profile portlet is configured to receive it, it will. In other words, a first generation event can trigger a second generation event can trigger a third generation event... and so on.
Posted at 04:21PM Feb 14, 2007 by Navaneeth Krishnan in Portlet | Comments[5]
Understanding Portlet 2.0 (JSR 286) - Part 1
Portlet 2.0 or JSR 286 is the latest revision of the Portlet spec. The specification work is still in progress and a early draft was published for review about six months back. However, this is the first time I am having a close look at this new spec – hence these notes.
Portlet 2.0 seems to be a good step forward for the Java EE portals landscape. It tries to address some of the key shortcomings of it's previous version. Portlet 1.0 was a pretty rudimentary spec which left out, perhaps intentionally, a lot of thorny issues and Portlet 2.0 seems to make up for it. That's good.
The first major difference you would notice is the redefinition of the Portlet lifecycle from a 4 phase one to a 6 phase one. The portlet lifecycle in Portlet 1.0 is defined thus:
Here, the init() and destroy() have precisely the same connotation as they do in the servlet world. init() is the callback for resource initialization and destory() is the callback for freeing up resources. The processAction() and render() methods are however interesting. Why would portlets require two different methods while servlets can do with a single service() method ? The answer lies in understanding the difference between the Servlet and Portlets.
A normal web application, being standalone, needs to display content only when it is acted upon i.e user clicking a link, user submitting a form, user scrolling a map that results in an Ajax request etc. On the contrary, a portlet application needs to display content not just when it is acted upon, but also when another portlet on the page is acted upon. This is because portlets typically share a page with other portlets.
Hence Portlet 1.0 defines two request phases. One to denote that a portlet was acted upon (processAction()). And the second to denote that a portlet needs to refresh it's content (render()).
To illustrate this point, consider the case where a user is accessing a portal page that has 10 portlets. If the user clicks a link on one portlet, only that portlet is acted upon. Hence processAction() is called only for that portlet. However, since the entire page needs to be rendered after this action, the render() method is called on all of the 10 portlets on the page. Hence the single user click will result in 1 processAction() call and 10 render() calls.
Let me be quick to point out these calls are not to be confused as separate HTTP requests. In reality, there is only one HTTP request/response between the user and the portal. This one HTTP request can be logically viewed as 1 +10 = 11 calls to the portlets. It would look something like this:
One key assumption in this 2 phase request processing model is that a portlet will change state only when it was acted upon i.e state change will occur only during the processAction() call. No state changes will occur during a render() call. In other words, render() is idempotent and processAction() is not.
Portlet 1.0 fails to take a few important things into consideration. Firstly, the assumption that portlets are always completely independent of each other is not true. Consider a Weather portlet and a Google map portlet being present together on the same portal page. It is perfectly natural for a user to choose a new location on the map and expect the Weather portlet to update accordingly.
Unfortunately, the spec does not provide any means by which one portlet can “notify” changes to it's state to the other portlet, even though both the portlets are present on the same portal page and are contributing to the same aggregated portal content. Hence developers are left with no choice but to resort to workarounds like writing to / reading from a shared memory space. Portlets within the same web application are typically coded to use the HTTP session. For portlets that are in separate web applications, matters are worse.
The second limitation is in the ability to serve dynamic resources. According to Portlet 1.0, a portlet has limited access to the underlying HTTP request and response objects. The rationale behind this restriction is that portlets are responsible for only generating fragments of content. It is the aggregation layer, namely the portal, that is responsible for assimilating these fragments into the final portal page. The spec overlooks the fact that there are valid usecases for a portlet to generate content that are not necessarily fragments. For instance, how would you write a portlet that can dynamically generate a pdf report on click of a link ?
Since the spec prohibits the portlet from accessing the outputstream of the HTTP response, the answer is not so simple. Many developers currently workaround this issue by providing a direct link to a servlet in the fragment generated by the portlet. When the user clicks the button, the servlet is invoked and it can write the generated pdf file back to the client. The problem with this approach is that the entire portal layer is bypassed and hence services provided by the Portal layer like say security is unavailable for such an interaction. Here is an illustration:
Lastly, Portlet 1.0 overlooked something that has become increasingly relevant today – asynchronous HTTP calls or Ajax. Portlet 1.0 was defined at a time when async calls were unreliable across browsers and relying on javascript for functionality was considered a bad thing. Times have changed and the spec needs to play catch up.
Portlet 2.0 addresses all the three key limitations that I mentioned . It also defines a whole lot of new things like Portlet filters, annotations etc. In my next blog entry, I plan to discuss some of these new features in detail.
Posted at 12:29PM Feb 01, 2007 by Navaneeth Krishnan in Portlet | Comments[8]
This work is licensed under a
Creative Commons Attribution-NonCommercial-NoDerivs 2.5 License.