Filthy Rich Portlets with ICEfaces and Liferay
When a portlet form is submitted, all the other portlets on the same portal page are forced to redraw themselves. In this presentation, filmed at the recent JSFOne Conference, I show you how ICEfaces Direct-to-DOM rendering provides a cure for this disruptive end-user experience, and how ICEfaces Ajax Push supplies a rich alternative for inter-portlet communication. Demonstrations are performed within Liferay Portal, a JSR 286 (Portlet 2.0) compliant portlet container.
The complete transcript of the presentation has been provided below.
Neil Griffin: OK, Welcome. This talk is titled "Filthy Rich Portlets with ICEfaces and Liferay." My name is Neil Griffin and I'm with Liferay Incorporated and I represent Liferay on JSR 314. We're going to talk about the two technologies today, how they play together and how you can do neat things with these two products.
Here's a general overview of what we're going to talk about. We're going to talk about what a portal is and what a portlet is. Then we're going to dive into Liferay Portal and some of its features. We're going to talk about JSF portlets and how you can use JSF in a portlet container like Liferay. Then we're going to move on and show how ICEfaces portlets are an improvement for the user experience over standard JSF portlets.
We're going to talk about different techniques for inter-portlet communication. And finally we're going to talk about using ICEfaces Ajax Push, sometimes referred at Comment or Reverse Ajax, for inter-portlet communication.
What is a portal and why do I care? What can it do for me? This is a definition that I came up with; I agonized over it for hours. A portal is a framework for creating websites that aggregate different types of content and applications. That's one definition. Portals are typically referred to as portlet containers. I've also heard the term "portal server" but I tend to favor portlet container for what a portal actually is.
What's a portlet? We learned what a portal is. A portlet, strictly speaking, is just a region of the portal page. It contains content or it might contain application functionality. So it might actually do something.
So with respect to the Java EE framework, a portlet is referred to as a web application. It's just a WAR, it's a web application, only more so. You have to add a descriptor file, allportlet.xml. And also, bridge, and were going to talk about that in upcoming slides.
So portals have pages. Just like any website, portal sites are made up of pages. And portal pages can contain one or more portlets. You can combine portlets on a page to create what I'm calling a "composite application." And we're going to see some examples of that.
Here's a picture, just an illustration of what I mean. This would be a portal page with three portlets on it: Portlet A, B, and C. Perhaps Portlet A would be on the left, Portlet B would be on the right, and also Portlet C. Portals typically let you lay out portlets any way you want, really.
There are standards for portlets. The first standard was released in October, 2003. That was JSR 168, and that's the portlet 1.0 standard. Very recently, in June of 2008, the JSR 286 standard was released. That's portlet 2.0. And we're going to talk a little bit about each one of these standards.
Let's talk a little bit about Liferay, what it is. It's an open source portlet container. I stress it's open source. It's been in development since 2000, and it has about 50,000 downloads per month. It's been downloaded well over a million times and is the leading open source enterprise portal product out there.
Here's a screenshot of what Liferay Portal looks like. Up here on the left, where you see that little dot there on the screen, it's very small. This is a portal page and that's a portal page right there. Those are hyperlinks that will take you to the different pages in the portal. And these little rectangular regions of content right here, they're portlets. Each rectangle is a portlet.
Liferay Portal has a nice feature in the upper right-hand corner. This is called the "dock" and it lets you navigate to different portal sites within the portlet container. And you can add pages dynamically with this little "add pages" link, if the portal user has been granted permission to do that.
So some of the features of Liferay Portal. It is standards compliant. It was compliant with JSR 168 portlet 1.0. And as of Liferay 5.0, it is now compliant with JSR 286, which is Portlet 2.0. It ships with over 60 out-of-the-box portlets. And lots of neat portlets for doing social networking, like friends or message forums or message boards, a shared calendar, Wiki, blog. Lots of great functionality that comes out of the box with Liferay.
And of course if there's something in Liferay Portal that's not there that you need, you can extend it with a customer portlet.
My favorite technology for creating portlets is JSF. JSR 127, the first mainstream version of JSF, JSF 1.0 that we were using, the spec was designed with JSR 168 in mind. So because of this, you can take a JSF web application, pretty much any web application, and run it as a portlet with little to no medication.
I attended a talk by Scott O'Brien. Is Scott here? There's Scott, OK. Would you agree with me on that?
Scott O'Brien: No.
Neil: No? All right. [laughs] I didn't think so. You do have to obey a lot of the JSF rules in order to make that statement true. But I do have the word "typically" there in order to qualify that statement. You can do some things that would prevent it from working in a portal. Liferay was one of the first portal vendors to provide support for JSF portlets, and that happened in May of 2005.
Now in order for JSF portlets to work as applications, you need a bridge. Liferay currently supports two bridges. One is from Sun, it's the Sun OpenPortal JSF Portlet Bridge, maintained by my friend Deepak. And the JAR file name for that is jsf-portlet.jar. So whenever you're looking at a portlet and you see that JAR right there, you know you're using the Sun bridge. That particular bridge supports the Sun reference implementation Mojarra for JSF 1.1. and 1.2.
Liferay also supports the MyFaces Generic Portlet Bridge that was written by Stan Silver of JBOSS. And the file name for that is MyFacesImpl.jar. It's not in a MyFacesPortlet.jar, it's actually classes found in the MyFaces implementation of JSF. But currently Liferay only supports MyFaces 1.1.
And of course JSR 3.01 is defining a standard portlet bridge for JSF portlets. And Scott, of course, is doing the reference implementation for that. That's going to be available at Apache.
I was mentioning the Portlet.xml file. This is an example, a fragment of markup that shows how to specify the Sun OpenPortal JSF Portlet Bridge. And you have to specify a name for you portlet with a portlet-name element right there. The thing I really want to draw your attention to is this portlet-class element.
You can see in bold, three. Com dot sun dot faces dot facesportlet. That is saying that when this portlet runs that's the class that we're going to instantiate. Portlets have three modes: view mode, edit mode, and help mode. Using these different configurations and it params right here, you can specify the JSF view that's supposed to render whenever you enter one of those three portlet modes.
Although portal pages can contain multiple portlets, we saw an illustration of that, only one portlet at a time can participate in form submission. And this is very significant. So if I have three portlets on a page, a, b and c, and I do a submit, a form submission on portlet a, and portlet b and portlet c-they didn't do anything wrong. They're forced to rerender themselves as part of a full-page submit process. My opinion is that this is a disruptive end-use experience. And this is where ICEfaces can come in and help us.
On the right is a JSF portlet. Very basic. It's just a form. It's a job application, so I'm going to apply for a job. What you'll see here is if I interact with the portlet on the left, and change some of the fields, and then interact with the JSF portlet on the right and hit submit, that's my little click right there, click. Then that's going to cause an HTTP post to take place, and that's going to cause the loan calculator to rerender itself. It's going to lose its brains and it's not going to remember anything.
So let's go to the demo. You can see I've got several portal pages defined here. I'm going to click on the one titled JSF. We'll log out to get a better -- here we go "JSF." So there's my loan calculator on the left and my sample JSF portlet on the right. So I'm going to do 15 right there, you see I've entered "15. And I purposely have the browser at about 2/3 height right there, because I want to persuade you that this is a full-page submit that is taking place.
So I know we can't see the entire portlet on the right, but standard JSF portlet, when I'm interacting with it here, I'm in the first name field. When I hit tab, nothing happens. When I hit last name, nothing happens. When I type in an email address, that's invalid. Hit tab, nothing happens. When I type in a phone number, that's invalid, nothing happens when I hit tab.
I don't find out when there's required fields or there's anything invalid until I click the submit button. Now, you notice I'm back to 30 years over here on the portlet on the left. And the portlet on the right, that's when I find out about my field double validation that took place. This is where ICEfaces is going to improve a user experience.
So with our first demo, ICEfaces is going to really help us with this. Well, what is ICEfaces? ICEfaces is an open source Ajax extension to JSF. JSF is highly extendable. There are so many features within JSF that are pluggable. Of course, the reference implementation provides default versions of them all. But you can mix and match these different features within JSF, like the navigation handler or the view handler. So ICEfaces takes advantage of these extension points within JSF. It's an Ajax application framework, and it comes with a robust suite of Ajax enabled JSF UI components.
Now you can build portlets with ICEfaces. ICEfaces is not just a technology for the servlet environment. It also works with portals. In particular, Liferay and ICEsoft have a partnership in place. For those of you who have an electronic version of the slides, you'll see there're some hyperlinks throughout here.
Those should work, in the PDF version you can click on them. That's a link to the article that talks about the partnership. And this partnership is in place in order to support the mutual customers and, to a great extent, the community, the different open source communities between ICEfaces and Liferay.
Another nice thing about this partnership is that the software engineers between the two companies are in connection with each other. If the folks at ICEsoft have a question about Liferay portal, about what's going on, get me on Instant Messenger and I have full access to the Liferay software engineers who are doing the core development work. It's been a very, very fruitful relationship. It's been very good for both products and for our mutual customers.
This is an important thing to remember. When you build a portlet with ICEfaces, it never, ever, ever, ever, ever does an HTTP post. Never. Instead, when you submit a form with ICEfaces, the form is submitted via Ajax. And because of this feature, portlets built with ICEfaces don't disturb the other portlets on the same portal page. We don't have that disruptive end-user experience. That's the end result, no disruptive end-user experience.
Before we saw a portlet .xml that described how to use the Sun bridge. This is a sample fragment of markup that shows how to specify the ICEfaces portlet bridge. And, of course, you can see in the portlet class element, there is a different class there. It's calling that ICEsoft.face's web app, so on and so forth, main portlet.
The other items here for the different portlet modes is similar in one respect, in that I can specify a JSF view for each one of these portlet modes. But the key is a little bit different. And this is where the portlet bridge standard, JSR 301, is going to help us. Because right now each one of the different bridges that are available all have different key names and it's a little bit of a pain. But once you choose a technology and a bridge, it's copy/paste from there. But JSR 301 is really going to help us stay consistent.
We need to understand a little bit about ICEfaces and how it works under the hood, and how it differs from standard JSF, particularly with regard to portals. So in a normal JSF web app or portlet, the requests scope is very short-lived. Very, very short-lived. It's duration is -- you know, the browser issues a request, and then the response comes back, and the scope is over. All that memory that was consumed goes to garbage collection.
And I love this feature, because what that means is that someone can be looking at an ICEfaces' portlet, and they can be working with it and working with it, and if they nuke their browser, then one last little XML HTTP request is sent to the server, and then ICEfaces is able to clean up that memory so that things go to garbage collection.
So JSF 2.0 is going to have this thing called viewscope and it's going to be very similar to the ICEfaces' extended request scope idea. Very similar idea. And this scope, this ICEfaces extended request scope, or we could call it viewscope, is a great match for portlets. It's perfect. It's a perfect marriage, particularly for portlets that don't participate in navigation from one view to another. With ICEfaces, when we build web apps with ICEfaces, sometimes there's no need for navigation rules at all, because we are able to turn on and off sections of the screen. You can do navigation rules if you want, but particularly for those that don't have any navigation rules, this is a great match for portlets.
During partial submit ICEfaces is going to invoke the JSF lifecycle. And this is very good for security, because there are a lot of financial institutions that use ICEfaces. And one of the things they like about it is from a security perspective, ICEfaces is always invoking the lifecycle, especially in regard to partial submit. So the thing you need to remember is when ICEfaces partial submit triggers it is a full submission. It is full in the sense that all of the editable fields are serialized and submitted. But it's partial in the sense that the form is only partially validated. So really, it's a full submit, but only partially validated, meaning that only the fields that have been visited by the user undergo validation.
That's very nice, because if I am on the first name field and I hit tab, I don't want to see required error messages next to every single field that I haven't visited yet, because that would be a disruptive experience. So here's a picture of the JSF lifecycle. When I do an OnBlur out of a field with an ICEfaces component where partial submit is true, we're going to run the whole lifecycle. We're going to start with restore view and go to apply request values and process validations, and we're going to try to execute the whole lifecycle. Here's the key. Here's the difference with partial submit with ICEfaces. See that little balloon there that's pointing to the process validations rectangle? Only the fields that have been visited during that. So, what ICEfaces does is it knows what fields have been visited and will only queue up faces messages for ones that fail validation for fields that have been visited.
Also, in the invoke application phase, which is the other balloon pointing right there, typically only action listeners are going to fire here. And that's just the nature of partial submit. It doesn't really make sense to have partial submit on a submit button. That's a false event. So partial submit would happen on something like a checkbox, maybe. When I check it and I want a partial submit to take place, and that might invoke an action listeners. So we're running the whole lifecycle here, only validating the fields that have been visited and just by its nature, only action listeners are typically going to fire in the invoke application phase.
ICEfaces also has a technology for rendering, which is called Direct-to-DOM. That's the ICEfaces' brand name for it. So standard JSF components render their markup directly to the response. But ICEfaces provides a render kit. Remember, JSF has all these great pluggable features in it. ICEfaces takes advantage of this with a render kit that causes the components not to render themselves to the response, but to a DOM on the server. Typically we think of a DOM as something that lives in the browser. ICEfaces renders it to a server-side DOM. We're going to see how that plays out.
We just looked at the lifecycle. The render response phase is the last phase of the lifecycle. So after that happens, ICEfaces is going to determine the differences between the DOM that is on the server and the DOM that is in the client. ICEfaces knows what's in the browser because ICEfaces sent it there in the first place. So if something happens during a partial submit and something in my model changes-remember that we're in a model view controller design pattern.
Then what's going to happen is ICEfaces will do a diff on the new DOM versus the DOM that it knows is in the browser, and will only send the incremental DOM changes. So the second bullet here says ICEfaces will then use the Ajax bridge to do that, to send the incremental DOM updates to the browser.
Here's an illustration of a typical J2EE web application-and this is true for a portlet as well. On the left side we may have a database or a web service, somewhere we're requiring data from. Maybe we're using EJB technology, or web services, consuming a web service. The ovals there represent JSF managed beans. And here in the orange rectangle there are different parts of the ICEfaces framework. Of course, it's JSF. Down here at the bottom we have a facelets page or JSP. And those views that are defined in a page subscription language contain references to ICEfaces components, like ICE:inputText.
Those components take advantage of the Direct-to-DOM rendering kit and write their markup into the server-side DOM. So here's a little animation that tries to convey that. Once it's in the DOM, ICEfaces computes the differences, and then via the Ajax bridge delivers the incremental updates to the browser. And again, this insulates Java developers from the task of writing Java script. Also, I don't have to specify in my JSF view what regions of the page I want updated. It happens automatically for me.
Portlet containers like Liferay portal, just by the nature of what a portal is, control certain elements on a page. They control the html element, the head and the body. So in order to insure that ICEfaces' portlets don't interfere with these, you need to use the ICE:portlet tag. Now this mainly comes into play if you're going to do navigation from one view to another. If you're going to do that then you need to surround your form with an ICE:portlet tag. This is an illustration right here. This is a sample fragment of markup, shows how to surround your form. You can see the ICE:portlet tag. The begin tag before the form, and also one after the form, closing tag.
So we have another demo. This is basically the same portlet, only an ICEfaces version of it. What we're going to do is we're going to position the mouse inside some of these fields on the right, inside this ICEfaces portlet. We're going to tab out, we're going to see how we learn about field validation problems right away. Nice rich user experience. We're going to type in things like a bad email address, a bad phone number. We're going to learn what the errors are right away. We can upload a file and ICEfaces has a technique called Ajax push which will show the progress of the file upload. And we're going to see how partial submit is making all this happen.
Also the other portlets on the page remain undisturbed. So here's the demo. Here's the standard JSF portlet that we were looking at, and here's the ICEfaces version of it. There's the same loan calculator on the left, so I'll work with it. I'll change that to a 15 year mortgage. Then I'll click over here on the right. I'll hit tab, and immediately the user is notified, hey, that was a required field. But I didn't see it next to all of them. That would be a pain. The user would not be happy with that, and so that's why we call it partial submit. It's full submit. Every single field value that's editable was serialized and submitted by Ajax. The lifecycle is executed. But only the fields that have been visited get phases messages added to the phases context.
If I type in a bad email address, I happen to have an email address validator on that field right there. I can hit tab, and it says please enter a valid email. Or I can type in a bad phone number and it tells me there are invalid characters in that phone number. I learn about it right away. This particular converter knows that if there's a 10-digit number input there that it's probably a United States phone number, and maybe I want it formatted in a particular way.
So notice when I hit tab the error message goes away and my value is converted for me right away. If I come down here and hit browse and upload a file, this is a very fast connection. My browser and server are on the same machine, there. Trust me. It went 0 percent, one percent, two percent, so on and so forth. And I get an Ajax push-Ajax push is updating the progress indicator for me. So I get a rich experience there. And also, when I hit submit here on the form, the value on the right, 15, is undisturbed. So the ICEfaces portlet is not interfering with the other portlets on the page.
I'm going to go back to the JSF version, the standard JSF version of this. If I type in 0123456789. That's a 10-digit number. Remember, with ICEfaces, I hit tab and it converted it right then and there. With a standard JSF portlet, I have to hit submit before the converter actually takes place. So it's the same web application, same portlet, it's just using ICEfaces instead of JSF.
Now there is a new portlet spec out, Portlet 2.0. We discussed that earlier. And it has some Ajax features in it. So I thought it was appropriate, during this talk, while we're talking about portals and ICEfaces, there is some Ajax in Portlet 2.0, and so can that help us? What's good about it? So Portlet 2.0 provides the ability to issue and XML HTTP request, that's what we call Ajax. XML enables the ability to fire these calls that go through the portlet container.
Portlet 1.0 you couldn't do that. The best you could do was fire an Ajax transaction that would go to a servlet within your portlet WAR. But now, with Portlet 2.0 if I fire this Ajax transaction, it actually goes through the portals WAR, through the portlet container. So the benefit is that I have complete access to the portlet state. It's very nice.
But there's drawbacks. If I'm using this technique to provide a rich experience for the end user, as the developer I'm probably going to manually update the DOM. There is no support for Ajax push with this, and it doesn't support Ajax-based inter-portlet communication. We haven't talked about what inter-portlet communication is, but I just put this one here for your edification, so that when we visit the slide later, you'll remember that it doesn't support Ajax-based inter-portlet communication.
So here's an illustration of what Portlet 2.0 Ajax features provide. The top rectangle, there, is a little web browser and it has a portlet in it, let's say portlet a. And let's say I'm in a field like first name, and I hit tab. I can then fire an Ajax transaction, which is illustrated by the arrow coming out on the left. So that creates and XML HTTP request. And that goes, you can see, to the portlet containers WAR, to a servlet in there, which has the ability to talk to each of the portlets that are deployed within my portlet container.
Once that talks to the portlet WAR, whatever results there are -- maybe it's new DOM updates, maybe just some JSON, it could be anything that's a list of results -- that is then delivered back as an asynchronous response, back to the web browser.
Now we're going to talk about inter-portlet communication. Well, what is it? We typically call it IPC. Bottom line, what it is, it's a technique for sharing data between portlets so you can build these composite applications. So I can take portlet A, portlet B, portlet C, put them on a page and WHAM, I've got a composite application where these things work with each other. So that's what I do. I aggregate different portlets and they share data. User interactions between, let's say, portlet A could affect the rendered markup between other portlets on the page, portlet B and portlet C.
There're two ways that you can achieve this. There's client-side IPC and server side. We're going to talk about the benefits and drawbacks of each. Here's an illustration. This is not with ICEfaces. This is with standard JSF or it could be any portlet technology, where perhaps I have a list of items on the left, or a button or a link. And I click on it. That will cause an http post to happen, and I want these two other portlets on the page to rerender themselves with markup according to whatever my selection was.
Some of the benefits is that this is a very, very, very simple publisher--that's a typo there, that should be subscribe-publisher/subscribe event mechanism. It's a very rich user experience. When the user interacts with portlet A, it's not a full-page submit. It's very nice. You can trigger a DOM update in portlet B or portlet C. This is nice. Network activity only takes place if Ajax is being used to acquire data. There's no full-page submit involved in order to do this.
Here are the drawbacks. Only one user and only one web browser can participate in this kind of inter-portlet communication. Why is that significant? We're going to see later on in the slides how ICEfaces Ajax push lets us not just do inter-portlet communication, but inter-portlet, inter-user, inter-browser communication. Very different, much more powerful.
That's client-side IPC. There's also server-side IPC. There're different kinds of server-side IPC. We're going to talk about the benefits and drawbacks of each.
Portlet 2.0 has this idea called public render parameters. That defines the ability for a portlet to set a public-think of it as a shared-parameter in the URL that is controlled by the portal. If you've never worked with a portlet container before, something that may not sit well with you at first, but does make sense when you think about the way portlets and portals are designed, is you don't control the URL. The portlet container is in full control of the URL.
So a public render parameter could be specified where--let's say I have portlet A on the left, portlet B on the right. I click on something that's a hyperlink, just an anchor tag. And perhaps that has an Article ID, can see the article ID, one, two, three, four. And that causes an http get to take place, or a post, perhaps. The whole portal page is redrawn and since this is an article, maybe a news article, then my news article would show up on the right.
So that's one technique for doing server-side IPC. The benefit is that it's very easy to implement. We're all used to this. As JSP programmers, if we've all done JSP, passing parameters from page to page, that's natural. We can do that in our sleep. The drawback is that it requires a full-page submit. And we've already seen how ICEfaces takes away that whole, disruptive full-page submit experience. So it does require a full-page submit.
This is my opinion, here. It's only practical for passing small amounts of data. Because otherwise you'd have a very, very, very long URL if you had a large amount of data that you, perhaps, had to encode in a URL. So like the ID of a record in a database, like article ID. And passing request parameters -- this is also my opinion -- from page to page is not very JSF-ish, or JSF-like. So if you're doing public render parameters with JSF, it's just a little bit out of the way we do JSF web applications.
Portlet 2.0 provides another way of doing server-side IPC. And it's a publish/subscribe mechanism. So we have publish/subscribe on the client, provided by Liferay. This is actually in the portlet standard. It's a publish/subscribe mechanism called Events. The benefit, here, is that the portal acts as the broker, and can distribute all the events. It's called the payload, which is maybe there's some shared data. Maybe it's not just article ID. Maybe it's this big chunk of data that I need to share with portlets. The portal acts as the broker for that.
Now, the drawback is-not always-it can be challenging to implement. In the simplest examples, it's not too hard. But it can be. It requires a full-page submit, and the payload, or the data, that I'm sharing between portlets, has to be serializable because when these events fire, it might be that I'm sharing data with a portlet that's in a different WAR in a different class-loader. So the portlet container has to serialize this data in order to get it over into the other class-loader for the other portlet to consume. So those are the drawbacks.
I do have a demo of this. This is courtesy of Sun Microsystems. It's a very nice, attractive demo. We'll see if it comes up. There we go. I have four portlets here. The portlet in the upper left is a listing-this is kind of a vacation tour type of page, here, that lets me browse through different tour packages. There are different links there, the Great Barrier Reef in Australia, Grand Canyon hike in Arizona, and so on. And if I click on one of those links, then I get details about the tour.
So I'll click on the first one. Oh, I'm not on the Internet, so I can't see the map that's being rendered here. In the portlet in the bottom right that would show a map. You can see if I scroll the browser down a little bit, it would be a little more obvious, when I click on the next one, that causes a full-page submit to take place before I see the other items show up in the browser. Trust me, that's the way it works. Demo. There we go. OK. So this is using events. It's a Portlet 2.0 feature, running inside a Liferay portal.
Now what I wanted to do and, Scott, we were talking about this earlier. When I wanted to do inter-portlet communication with JSF, the natural thing that came to my mind, oh, I just put it in this session. JSF has this scope which is called session scope, and it's how I can share data between my different JSF views. So, I'll just put it in session and it'll work. Well, it didn't.
This is what was natural, I thought, for a developer to try. Maybe I don't think like a normal JSF developer, but it doesn't work. Why not? Because the portlet API defines session scope in two different ways. The main name can be a little confusing, especially if you're used to JSF terminology. It has Portletsession.Portletscope. That means that data cannot be accessed by portlets. Or Portletsession.Applicationscope, which means that data can be accessed by other portlets.
So, JSF portlet bridges including the ICEfaces bridge--they follow the lead of the other bridges out there--and including JSR 301 default JSF session scope to be Portletsession.Portletscope. I was talking to Scott earlier, and 99 percent of the time that's the scope you want, Portletsession.Portletscope, except if you're doing inter-portlet communication, and then you don't want it.
Currently there's no way to specify that you want this other kind of scope. So, I can't in my Facesconfig.xml put a scope on my managed bean called "Portlet Application," or something like that. There's nothing there yet, but hopefully we can get a feature like that in there. So, consequently JSF session scope doesn't work for inter-portlet communication.
But, you see, a JSF portlet can take matters into its own hands and just do it brute force, and store data for inter-portlet communication in the Portletsession.ApplicationScope. So, the benefit of doing this is that we're sharing data in a stateful user session that's managed by the portal. I don't have to worry about memory management. The portal container and the servlet container are going to be managing that for me.
But the drawback is that I can't share data across portlet WARs. I didn't mention this earlier. A portlet lives inside of a WAR, but it is not necessarily a one-to-one relationship. I can have a WAR with 10 portlets in it. It doesn't have to be one WAR per portlet. But if I do have portlets defined in separate WARs, then I can't share data using this, because it's scoped within the WAR.
Now, there's also a way where you can use JSF application scope to share data. So, if I put it in the JSF application scope, the benefit is that it's not restricted to a single user. We have an example later where we're going to use ICEfaces to do chat inside of a portlet, and we're using application scope to store that data.
The drawback is that you can't use the stateful features of the session to rely on memory getting freed up and things like that. That's a drawback. And you also can't share memory between different portlet WARs.
If you need to share data between WARs, Liferay portal--this is a feature of Liferay, not a portlet standard thing--normally lives in the root context of the server container. So, if you're using Tomcat and you download the Liferay Tomcat bundle, in the webapps folder there's a folder called "root." That's where Liferay lives.
And so, when it's running what Liferay provides is the ability for you to create portlets as separate WARs. And in these separate WARs, you can use the portal class invoker. This is a special utility that Liferay provides that knows how to go into different class loaders, and get data and Java references that are in different class loaders, which could be the case if you're trying to share data.
So, you can use the portal class invoker utility to provide access to data that lives in Liferay's root context. For more information, I have a hyperlink here. I have a blog entry that I've done that shows you how to implement this feature. It was too technical and too detailed to go into for this presentation. So, that's there for your reading.
We have another demo, and this shows how to use JSF to do inter-portlet communication in the standard way. This is server-side IPC. Now, what we're going to do is, we have three portlets. In the upper-left we have a portlet called customers. On the right, those are bookings. This is like for a travel agent, where a travel agent is going to work with multiple customers.
It's maybe even at the same time, because they're switching back and forth between different phone calls and talking to different people. Maybe they've got customers on chat, or what have you. And so, they're going to click on these different customers in the customer portlet on the left, and they want to see the booking information for the planned vacation on the right.
Also, I've got the loan calculator on there just to show that when I enter in a value there, and I use this type of inter-portlet communication, the page is a disruptive user experience.
So, here's the demo. What I'm going to do is come down to Years here and type in 15 and hit Tab. Then, I'm going to go to this customer portlet on the left, and I'm going to click the Edit button. That's going to issue server-side inter-portlet communication and update the list on the right.
When I do that, you can see that we had a whole page refresh. The loan calculator on the left is back to 30 years. It lost my 15. But I did have successful inter-portlet communication, and the portlet on the right is now reflecting my selection that I made on the left. I can do things, like if maybe there's a typo in the name of my customer, I'll just change this from Brian to William over here.
We saw how I can do inter-portlet communication from the left to the right here. If I tab down to the bottom, there's a Submit button. You can see in the portlet on the left that the name has been updated to William. So, it can be bi-directional. All we're doing here is just updating JSF model data. It happens to be in the Portletsession.Applicationsession scope.
ICEfaces has this technology called Ajax push, and I have a diagram that we're going to look at that explains this technology. ICEsoft pioneered Ajax push. A lot of people will call it Comet or reverse Ajax. ICEface's Ajax push predates those terms. ICEsoft was hard at work on this before those become popular. This technology, Ajax push, was part of the design of ICEfaces from the very beginning. It's not an afterthought. So, the ICEfaces framework provides this feature out of the box in a seamless way.
And so, we can use Ajax push to trigger what we call server-initiated rendering. Some of you may have attended Tim Goddard's talks earlier today and yesterday, and learned about ICEfaces and Ajax push. We're going to see a little illustration of what Ted was talking about.
There could be two different types of events that we might want to intercept in order to update all of the browsers. Not just one, but all of them. The user in one of the browsers, say the one on the far right, may click on something. That would be a user event that ICEfaces is notified of, or we could have a server-side event that could take place. In either case, ICEfacs knows the web browsers that are looking at a particular web application. It knows exactly what's in their DOMs, and it can do a DIF using the D to D rendering engine, and then push the incremental updates into each one of the browser windows.
Now, I'm a little biased here. I can't think of any drawbacks, but perhaps there are. I can't think of any.
So, here's a little illustration of using Ajax Push for inter-portlet communication. We have a portlet on the left and two portlets on the right, and I'm going to click on something on the left with no full page submit; I'm just going to click on something on the left, and the portlets on the right would get incremental DOM updates. They wouldn't re-render everything, necessarily, just the part of my model that has changed, that has effected the rendered markup in some way.
So we have another demo. This is the same thing we saw with standard JSF, only it's built with ICEfaces. OK, and I'll expand the window here. So, here again, I have a list of customers on the left, and the bookings on the right. I'll come down here and I'll change the number of years to 15 again, and I'll select a customer. Remember, in the other demo with standard JSF, when I clicked on an item, it caused that 15 to revert back to 30 because it was a full page submit. But when I use ICEfaces, it says 15. It doesn't interfere with the other portlet.
What happened is I have partial submit on a row selector, and that triggers an Ajax transaction to go back to the server, it invokes the Ajax Push mechanism, because it knows that the portlet and the portlet on the right are sharing data. What I've done in my model, for example, if I click on the second customer here, Liz Kessler, is all I have done in my model is I have changed the selected customer that happens to he in a Java.util.list. That's it. I have something in there called "selected customer," I change it, and my markup re-renders itself according to the model change.
The nice thing about this is if I change the name, let's say this customer wants to be Elizabeth, if I hit Tab, that will cause partial submit, watch the left, the name for Liz Kessler is now Elizabeth. So, I have bi-directional inter-portlet communication taking place in a rich UI that doesn't disturb other portlets. Similarly, I may be working with all three customers at the same time. I can come here to the first booking, you can see that Elizabeth Kessler has three bookings. This is the first one. I'll change that to airfare, and I'll change the date right here to September 10th, and coming back on September 12th, I'll switch back to Brian Green.
Brian Green has more bookings. Brian Green has one, two, three, four, five bookings. That's only because the Java.util.list has five elements, versus three. I could do some changes here, maybe in the third booking; this is going to be a cruise. If I go back to Elizabeth, it remembers, because the data lives in my model. The model lives in ICEfaces extended request scope, which is still alive. We're sharing data in the portletsession.applicationscope. So, you can see how this is a very, very attractive technology to use for inter-portlet communication.
We have one more demo, where this is actually a portlet that comes when you download ICEfaces. There are some sample applications that are there, and this is a chat portlet that's there. You can build it for a variety of different technologies. I built it for Liferay. What we're going to show is we're goingto put data in JSF application scope, and see how different portal users can chat with each other.
Here is the ICEfaces chat, right here. I have Internet Explorer running at VM right here. I'm goingto log in to Liferay portal with IE. So, this is running a Mac OS 10 and I'm running Firefox on Mac OS 10. I have a VM that's running Windows XP, running IE, all on the same computer. So these are completely different operating systems, completely different browser technologies.
So, here in the chat portlet, I'm logged into Liferay as Neil Griffin. I'm going to say IE Neil Griffin. Log in, and there's a little chat log right there. You can see participants, on the left is IE Neil Griffin, and I joined at that time. If I go back here to my Firefox window running on the Mac I can say that this is Firefox test. This is the test. Joe Blogs is the Liferay test user. I'll log in there, and I cans see that I now have two participants in my chat. I have Firefox test running on the Mac, and I have IE Neil Griffin running on Windows, and we can chat with each other. "Hi, from Firefox on the Mac," Send. Of course, I see it in the chat log in the portlet that I was just using, but do I see it over in IE? I do. See, "Hi," from Firefox on the Mac. I can say, "Hello, back, from IE, on XP." OK.
Hello, back, from IE, on XP. That's using JSF application scope to share data. Between the same portlet, different users, different browsers, different operating systems. This could have any number of users. This portlet could be configured to have chat rooms so that different users in my organization could be using the portal and all chatting with each other. Nice collaborative Web 2.0 example.
Now, Liferay and ICEfaces can be deployed in a variety of different ways. With regard to servlet containers, you can use Apache Tomcat, or Webtide Jetty. There are a variety of these database servers are all database servers that are supported by Liferay portal. ICEfaces doesn't require a database out of the box. Application servers that are supported are GlassFish, of course, JBoss, BEA has been acquired by Oracle, so WebLogic, Oracle application server WebSphere, and a variety of different operating systems that will support some variant of the Java virtual machine.
So, in summary, ICEfaces portlets provide a rich UI that don't disturb other portlets on the same portal page, and Ajax Push, I would argue, is a compelling technique for IPC, especially within Liferay portal.
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)