ALI Install Issues on Fedora Core 5

Note: I don’t think this is officially supported, so YMMV.

I encountered a problem installing ALUI G6 on Fedora Core 5. Just for the record, it’s not a problem with ALUI — it’s a problem with InstallAnywhere, the software that BEA uses to install ALUI.

Here are the errors I got:

[[email protected]]# ./PlumtreeFoundation_v6-0
Preparing to install...
Extracting the JRE from the installer archive...
Unpacking the JRE...
Extracting the installation resources from the installer archive...
Configuring the installer for this system's environment...
awk: error while loading shared libraries: libdl.so.2:
cannot open shared object file: No such file or directory
dirname: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory
/bin/ls: error while loading shared libraries: librt.so.1:
cannot open shared object file: No such file or directory
basename: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory
dirname: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory
basename: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory
hostname: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory

Launching installer...

grep: error while loading shared libraries: libc.so.6:
cannot open shared object file: No such file or directory
/tmp/install.dir.17585/Linux/resource/jre/bin/java: error while loading
shared libraries: libpthread.so.0: cannot open shared object file:
No such file or directory

I resolved these errors by doing the following:

[[email protected]]# cat PlumtreeFoundation_v6-0 | sed
"s/export LD_ASSUME_KERNEL/#xport LD_ASSUME_KERNEL/" >
PlumtreeFoundation_v6-0.new

[[email protected]]# chmod a+x PlumtreeFoundation_v6-0.new

[[email protected]]# ./PlumtreeFoundation_v6-0.new

This may work to get ALUI installed on other unsupported flavors of *nix, although I’ve never tried it, so again, YMMV.

Comments

Comments are listed in date ascending order (oldest first)

  • once you got it installed how did it run on core 5?

    Posted by: phil- on April 13, 2007 at 12:30 PM

  • It ran pretty well aside from the occasional JVM segfault, which I could have probably fixed by upgrading to the latest 1.4.2 JVM and plugging that into Tomcat 5, rather than running the OOTB bundled Tomcat/JVM supplied by BEA.

    Instead, I’ve switched to Ubuntu (with Oracle XE), which is a great platform because, for the most part, it just takes care of itself. It’s like having RHEL with a lifetime subscription to RHN, but without actually paying for it! 😉

    Posted by: bucchere on April 14, 2007 at 6:17 AM

Fedora Core 5 Support for Intel Pro Wireless (Centrino)

I bought a new Gateway MP6954 Laptop yesterday and decided to give Linux another go. This time I told myself: I’m not even going to attempt to run any Windows applications using Crossover Office or anything else. I’m just going to go with what works best: httpd, Tomcat, Java, PHP, Perl, Ruby, Oracle, MySQL, etc.

I installed Fedora Core 5 again (kernel build 2.6.15-1.2054_FC5smp) from the same CDs I used last time and it installed and came up cleanly, but with no wireless support. There is very little documentation about running Linux on my particular laptop model, but the wireless hardware (Intel Centrino/Pro Wireless ipw3945) is fairly commonplace and, according to the many sources I referenced, it’s “well supported” by Linux. Intel even offers a driver for it, but it’s a source-only distribution.

According to the install guide for the driver, I first needed to download and compile the IEEE 80211 subsystem. I later found out that in most cases, doing so is a bad idea. Compiling the subsystem (version 1.1.14) and then the driver (version 1.1.0) led to runtime incompatibilities — “Invalid Module Format” was the exact error. However, against the 80211 module included with the 2.6.15 kernel source, the driver wouldn’t even compile. So I was in a bind.

I needed to find an IEEE 80211 subsystem that was compatible with the 1.1.0 version of the driver. The answer was actually more simple than I thought. All I needed to do was upgrade to the latest FC5 kernel 2.6.17, install the latest kernel sources (yum install kernel-devel) and then build the driver from there. These are the instructions I followed.

And just like that, I had wireless support for my new laptop under FC5. Now only if I could get the sound card working . . . .

ALUI Portlet Pagination Cookbook

A coworker asked me how to write Plumtree portlet pagination (i.e. showing records in a UI and allowing the user to move from page to page, n records at a time) the other day and the ensuing discussion made me rethink how I’ve always done this and consider some new options. In this post, I attempt to shed some light on a very simple concept that turns out to be quite interesting in terms of implementation.

First, let’s consider some of the ways developers typically add pagination to standard web applications, forgetting about portals and portlets for a moment. Let’s call n your page size, i your page number and t the total number of records. On the first page, you might see n records laid out with alternating row colors and a 1-n of t marker to show you were you are, e.g. Now Showing Records 1-5 of 45. There’s probably also a next button and a back button (grayed out for now), a first page button (also grayed out), a last page button and maybe even a “fast-forward” button to move forward several pages at a time.

A very easy way to implement this in a standard (non-portal) MVC Java/J2EE Web application would be to carry some state, say i (the page index), on the querystring. For example, say you have a record viewer servlet called “RecordView” running on a Java-enabled Web application container such as Tomcat. You could have something like http://bdg-plumtree:8080/bdg-plumtree-context/RecordView as your URL. Your servlet code snippet might look something like this:

import javax.servlet.*;
import javax.servlet.http.*;

...

private Model model;

protected void doPost(HttpServletRequest request,
                      HttpServletResponse response)
                        throws IOException {

    //if you didn’t specify a page argument, display the
    //first page (pageIndex = 0)
    int pageIndex = request.getParameter("i") == null ? 0 :
      Integer.parseInt((String)request.getParameter("i"));

    //make a call into the data model to get the i-th page
    //and put the results in the request
    request.setAttribute("results", model.getResults(pageIndex));

    //forward to your view (JSP)
    request.getRequestDispatcher("view.jsp").forward(request, response);
}

In the view, you would simply print out the results, line-by-line, perhaps alternating row colors to make it easier to read. Then you need to display the little marker that tells you what page you’re on and the buttons to get next/back/to the end/etc. The logic to figure out what buttons to display and which buttons to gray out is a little involved, but it’s mundane enough that I don’t think I need to cover it here. The important part for this discussion is what’s in the links that actually take you forward and (soon) back. The answer there is simple enough — just create links that append the appropriate querystring and you’re all set. Here’s an example:

<a href="http://bdg-plumtree:8080/bdg-plumtree-context/RecordView?i=<%=i + n%>">Next</a>

So far so good.

The problem is that when you try to do this in an ALUI portlet, you don’t have direct access to the querystring, so you can’t use this approach. You need to store the variable i using some kind of state mechanism. Here are your options:

  1. The HTTP session
  2. A portlet setting
  3. A session setting (G6 and up only)

There are tradeoffs between #1 and #2 but #3 offers a good compromise. Let me explain.

If you use the HTTP session, your users’ page setting (i), will only persist for the life of the session, which is probably desirable. But, if you’re using the Plumtree caching model for portlets (such as expires or last-modified/etag caching), you can’t cache this portlet at all, which is definitely not desirable. The reason is that every page, regardless of the value of i, will have the same cache key.

To implement session-based pagination, you only need to change two lines of code:

request.getParameter("i")
becomes request.getSession().getAttribute("i") and your anchors that control the moving from page to page now need to point to a different controller servlet. (Remember, you don’t have control over the query string any more in portletland).

<a href="http://bdg-plumtree:8080/bdg-plumtree-context/ChangePage?i=<%=i%>">Next</a>

The ChangePage servlet simply sets the session attribute and then calls return to portal as shown here:

request.getSession().setAttribute("i",
    request.getParameter("i"));
PortletContextFactory.createPortletContext(request,
    response).getResponse().returnToPortal();

The only way to unique-ify the cache key, therefore caching your portlet appropriately, is to go with approach #2, the portlet setting. Now, when users advance i, they will be creating a new cache entry for each value of i (since settings are always part of the cache key). The drawback is that the users’ page settings (i) will persist longer than the life of the session. In other words, they could be browsing page 5, then they could leave the portal for several days, come back, and still be on page 5!

For your view:

PortletContextFactory.createPortletContext(request,
  response).getRequest().getSettingValue(SettingType.Portlet, "i");

And for your ChangePage servlet:

PortletContextFactory.createPortletContext(request,
  response).getResponse().setSettingValue(SettingType.Portlet, "i", request.getParameter("i"));
PortletContextFactory.createPortletContext(request, response).getResponse().returnToPortal();

G6 offers a nice compromise: the session setting. (If I had to guess, I would say the session setting was designed expressly for pagination.) With a session setting, you get the best of both worlds: a page setting that lasts only for the duration of the session but also a unique cache key so that you can effectively cache your portlet.

For your view:

PortletContextFactory.createPortletContext(request,
  response).getRequest().getSettingValue(SettingType.Session, "i");

And finally, for your ChangePage servlet:

PortletContextFactory.createPortletContext(request,
  response).getResponse().setSettingValue(SettingType.Session, "i", request.getParameter("i"));
PortletContextFactory.createPortletContext(request,response).getResponse().returnToPortal();

All of these methods have one drawback — they refresh the entire page on every portlet pagination click. So . . . stay tuned for an upcoming post on AJAX-based portlet pagination.

Comments

dev2dev comments are listed in date ascending order (oldest first)

  • This is a good start for everyone on Java. If you are like me and are a .NET developer at heart, you will be glad to know the .NET Web Control Consumer supports the use of a MS data grid control. All that is needed is for the developer to drag one of these objects onto the form, hook it up to a data source, and presto, you get pagination, storability, edit, and any other thing you always wanted from a table.

    Andrew Morris – [email protected]

    Posted by: drews_94580 on August 15, 2006 at 2:03 PM

  • It’s true — in many ways, .NET is way ahead of Java. I have only a little experience with the .NET Web Controls and the Control Consumer, but from what I’ve seen, there’s a lot of power and flexibility there. My post was making the “I want to roll my own pagination in Java” assumption. 🙂

    Posted by: bucchere on August 16, 2006 at 8:30 PM

Cracking open ISO files

I’ve been doing a lot of installing and re-imaging lately 🙁 and I’ve had to work with ISO files quite a bit. I haven’t found any Windows freeware that writes ISO files to CDs that actually work. However, I did discover that WinRAR has built-in support for extracting ISO files onto your hard drive.

It won’t, however, help you burn an ISO to a CDR, but hopefully with this info you might not have to!

(By the way, Mac OSX has native support for burning ISOs to CDs built into the operating system.)

Adventures in desktop linux

I’ve had such a good experience using Fedora on several of bdg’s enterprise systems (SugarCRM, Subversion, Bugzilla, Vetrics, Connotea, etc.) that I thought I would give desktop linux a shot.

What a mistake.

Actually, it was a good learning experience. But still, a mistake.

First I download Fedora Core 5 (Bordeaux) using BitTorrent. My first problem was mastering the ISO files to CD. Windows has no native support for this (surprise) and for the life of me I couldn’t find a free product without filesize restrictions or other issues. Finally I remembered that I had a purchased a license for Sateira DropToCD some time ago, so I attempted to use that miserable excuse for a program. I tried to burn the five CDs at 24x (~10 minutes each) and my computer would not recognize them. The CD-Rs, once burned, were useless, yet Windows did not show any data on them nor a volume label.

I did a little Googling and then remembered that I needed to burn at 4x in order to get Fedora Core 4 (and Solaris x86 — another mistake) to work. So I tried that (at ~30 minutes per CD) and again, total failure. Finally I used a real operating system, OS X, running on my wife’s Mac laptop, to create the ISOs. (Of course OS X has built in support for ISO burning that works like a charm.)

After all this nonsense, I was finally ready to install FC5. So I backed up all my company files, music, photos and other stuff to my Western Digital 250 Gb external firewire drive and off I went.

I must say, there are some nice things about FC5. Unfortunately, it’s a short list:

  1. The installer, Anaconda, is awesome.
  2. The graphic design is beautiful.
  3. Wireless networking just works.
  4. Firewire just works.

So I was off to a running start. But here is where my problems began. At the top of my shit list is CodeWeavers‘ CrossOver Office. What a complete piece of garbage. From all their press releases, I was led to believe that they actually supported some useful Windows programs such as Office and, more recently, iTunes on various flavors of Linux. Don’t believe what you read. It’s all lies. Damn lies.

I started with Office 2003. That just failed utterly and completely. I wasn’t about to go back to Office XP, so I gave up on running M$ Office. FC5 comes with OpenOffice, which claims to support Word, Excel, etc. so I figured I would just use that.

Next I moved to iTunes. First off, installing it is a series of hacks and kludges. Upon following these ridiculous instructions, iTunes actually launched! But:

  1. All my playlists were gone, even though I repeatedly pointed iTunes to my backed up iTunes Music folder.
  2. The best feature in iTunes, search, didn’t work — the search box was grayed out.
  3. A basic feature — scrolling — was inconsistent and buggy.
  4. It crashed about 10 times before I completely gave up on it.

So now I had limited options. I decided that I would give up on purchasing DRM music through the iTunes store (and save about $500/yr in the process) and switch to Banshee, which claimed to be everything that iTunes was minus the music store.

Okay, so music is just music. But what about e-mail? I’m totally addicted to Outlook — the proof is my 1.5+ Gb .pst saved mail file. Without CrossOver Office running Outlook, I had to fall back on Evolution or Thunderbird. Access to saved mail, however, was a showstopper. To use my gi-normous .pst file in a non-M$ program, I needed to convert it to MBOX format. That proved impossible. Or at least not possible within my own personal constraints of time, patience and most importantly, sanity.

First I tried Thunderbird, because I remembered using its Outlook .pst conversion program. After struggling for a long time with compilation issues, linking issues/missing dependencies (including the wrong version of libstdc++) and segfaults, I finally got the ol’ T-bird working on FC5. But to my disbelief, the option to import a .pst was missing. After some Googling, I found out that Mozilla’s hairbrained implementation actually relies on MAPI, so you need to have Outlook installed and configured on the machine with Thunderbird in order to convert from .pst to MBOX.

I tried various other programs, including a useless dungheap called MailNavigator. I also tried hand-compiling a C program called libpst that was supposed to work and didn’t. I was beginning to think that my .pst file had been corrupted, but that was impossible because it was running fine in Outlook.

After all this nonsense, I used my wife’s laptop to download a DOS book disk with fdisk, deleted all my partition info, and now here I am back on Windows XP.

Lessons learned:

  1. Linux is not ready for the desktop, even if you’re a hardcore developer.
  2. Don’t believe anything CodeWeavers say about CrossOver Office. It just doesn’t work. Period.
  3. Windows, for all its faults, is actually not that bad. I can’t believe I just said that, but it’s true. 😉

Integrate your iPod with your car — the right way

I normally restrict myself to writing about ALUI (Plumtree) topics, but I just can’t resist sharing my thoughts on a recent purchase I made that has changed my life (no kidding).

Up until Monday of this week, I’ve been a happy iPod user (3G, 20 Gb) who enjoys using his iPod in the car but who has never been completely happy with the available options for iPod automobile integration. I started with Griffin’s iTrip, a little cylindrical module that plugs into the top of an iPod and broadcasts the amplified sound to an FM frequency of your choosing. There are several problems with this approach:

  1. The sound is amplified — it would be better to start with a flat signal.
  2. You have to change frequencies when you travel because of interference from other stations.
  3. It’s incredibly difficult to change broadcast frequencies and there’s no way to tell which frequency you’re on.
  4. You have to operate the iPod while driving, which can be dangerous.
  5. You need to purchase separate accessories (such as a cigarette lighter charger) in order to keep the iPod juiced.
  6. You have to deal with messy cables and other electronica in your car that you need to remove and hide in the trunk when you park and leave the car.

Recently I purchased a better integration kit (also from Griffin) called the Road Trip. This unit addresses several of the problems, but not all of them.

  1. The sound is flat — it connects to the dock rather than the audio out.
  2. You still have to change frequencies when you travel.
  3. It’s super easy to change frequencies (and there are even presets) and there’s an LCD that tells you what frequency you’re on.
  4. You still have to operate the iPod in the car, but at least there’s a nice support structure that holds the iPod in a comfortable position for the driver.
  5. It automatically charges the iPod with the included cigarette lighter adapter.
  6. You still have to have the iPod in the car, although it’s more contained because the charger, FM modulator and holder are all part of the same unit.

So as you can see, I was getting closer to the ultimate iPod/car integration solution, but I still hadn’t arrived at it fully.

Until Monday.

After some extensive searching and several calls to the local BMW dealership, I found a product called the USA Spec iPod Adapter that solves all of my iPod/car integration woes, was easy to install, and well priced at around $130 (including tax and shipping) from Bavarian Autosport.

It works with most BMWs (as long as there is no navigation system installed) and it installs in literally 15 minutes.

To install it, I simply removed my car’s factory-installed, trunk-mounted 6-disc CD changer (which I’ve never used) and pulled out the two cables that power the unit and connect it to my Harmon Kardon audio system. I then attached these two cables to a cable (included with the adaptor) which plugs into the adapter. From there, there’s another cable that connects the adapter to the iPod. The whole unit (adaptor + cables + iPod) is safely concealed in the trunk.

I can now operate the iPod from my audio console, which sees the iPod as a CD changer. Playlists BMW1 through BMW4 are mapped to CDs 1-4, CD 5 plays all tracks on the iPod and CD 6 activates the auxillary RCA input jack into which I could plug satellite radio or any other component. The USA Spec adapter also charges the iPod, but is smart enough to shut off one hour after the car gets turned off to prevent drain on the battery.

So I’ve finally found it — the ultimate iPod/car integration kit. No more FM modulation, great sound, easy installation, easy and safe operation and the iPod is where it belongs: in the trunk!

Watch for deprecated methods in the G6 server API

We’re doing a G6 upgrade at one of our customer sites and we noticed that one of our PEIs (that used to set a user preference) was dying due to our use of APIs that worked in 5.0.4 but no longer work in G6.

(Just for the record, I guess I have a different idea of the meaning of deprecated when it comes to APIs. I thought that if you deprecate an API it means “please don’t use this as it might be removed in future versions of the API.” For BEA AquaLogic, I guess it means “this method just doesn’t work any more.”)

Here’s an example: AddPersonalSetting has been replaced by AddPreference.

public Redirect OnAfterLogin(Object userSession, ApplicationData applicationData)
{
IPTSession session = ((IPTSession)userSession);
session.GetMyPages().OpenPage(0 - userId)
.AddPersonalSetting("UserSettingName", "UserSettingValue");
}

Here’s the new G6 way to do this:

public Redirect OnAfterLogin(Object userSession, ApplicationData applicationData)
{
IPTSession session = ((IPTSession)userSession);
session.GetSessionInfo()
.AddPreference("UserSettingName", "UserSettingValue", 0);
}

Passing information between Plumtree portlets

This matter has been a subject of a great deal of debate among many of our customers, so I thought I would share my thoughts on the topic. What better place to do it than here on bdg’s Plumtree blog? 😉

This post expounds on the many methods you can use to pass information from one portlet to another or, in the more simple case, just store information temporarily for use later by a single portlet. There are at least three approaches I’ve found that accomplish this: the Plumtree Settings approach, the PCC/Adaptive Portlet approach and the backend-system approach. As you’ll see, there are also hybrids of these approaches that may work best for you, depending on your environment. I’m going to describe each of these in detail, but first, allow me back up a bit and explain the problem.

You’re building what Plumtree now calls an IAM (Integrated Activity Management) application. If you don’t think you are, check out this example (requires Flash). If you thought you were building an SOA (Service Oriented Architecture) application, well, a rose by any other name is still a rose, right? Basically, IAM, SOA and Composite Applications all mean the same thing to me, more or less. The way I define them is: you’re building an application that allows your end-users to achieve a business goal, say, an employee enrolling in his or her company’s health benefit plan. In order to pull this off, you need to build integration with several different corporate systems including perhaps getting an employee record from the HR system, deducting pre-tax payments from the employee in the company’s payroll system, and then registering the employee with an external site’s web services-based API to enroll him or her with the third-party benefits provider.

In order to pull this off in Plumtree, you’re going to need to design and build several portlets and perhaps a couple community pages or even multiple communities. Exactly how many portlets and whether to use one page, more than one page or one or more communities is one of the many decisions you’ll need to make in designing your application. All your decisions, BTW, should depend on how you want to structure your navigation and your screens to make your application usable. These decisions should not be ruled by what Plumtree is or isn’t capabile of doing but instead by how you’re going to make it easy (and even fun) for your employee to enroll in health benefits.

So, all that business aside, you’ve designed your application and it uses more than one portlet on, say, different communities. In keeping with our example, let’s say the first portlet allows the employee to confirm or update all his or her personal information and the second portlet asks the employee to pick amounts to be deducted from his or her paycheck for premiums and flexible spending. Now you’ve created at least two technical problems for yourself: 1) how do you get from the Employee Information community to the Payroll Management community and 2) how you get information (or state) from the Personal Information portlet to the Flex Spending portlet?

The answer to the first question is easy – use the pt:openerLink markup tag to create an URL that takes you from the Employee Information community to the Payroll Management community.

The answer to the second question depends on what type of state you need to pass, what form it’s in and how big it is. I’ll keep those things in mind as I discuss the three approaches to passing state.

Plumtree Settings approach

This approach works well if you have small bits of state that can be represented as strings and if you don’t mind having the page refresh (which it’s going to do anyway as you move from one community to another). To pull this off, you’ll need to use a User Setting, a type of setting that is unique for every user but that can be read (and set) by any portlet. First, you’ll need to settle on a name for your User Setting and then configure your Plumtree Web Service to “listen” for that setting. To do this, you need to open your Web Service editor, go to the Preferences page and then under where it says “Add specific preferences that you would like sent to this Web Service,” enter the name of your User Setting. You’ll need to do this in all the Web Services that need access to this information.

In our benefit enrollment application, the most likely thing we’ll need to pass is the employee ID, which shouldn’t be hard to represent as a string. Here’s what the code might look like in the Personal Information portlet:


PorltetContextFactory.createPortletContext(request, response).getResponse().setSettingValue(SettingType.User, "EmployeeID", employeeID);

And here’s the code for your Flex Spending porltet:


String employeeID = PorltetContextFactory.createPortletContext(request, response).getRequest().getSettingValue(SettingType.User, "EmployeeID");

PCC/Adaptive approach

The Plumtree Settings approach works well in this case, but what if you wanted to do this without a page refresh? Then I might suggest looking at two different adaptive portlet patterns: the Master-Detail pattern and the Broadcast-Listener pattern. These patterns do exactly the same thing, but with one major difference. The Master-Detail pattern assumes that you have no more than two portlets and that your two portlets are on the same page and the Broadcast-Listener allows you to send information to portlets on different pages and to broadcast from one portlet to many listener portlets.

Here’s how the PCC/Adaptive approach fits into our example: when the employee finishes updating his or her personal information in the Personal Information portlet, he or she is expected to click a button or link to indicate completion. The button or link needs to be tied to a javascript method that passes the employee’s ID to a PTHTTPGETRequest for the content (or a segment of the content) of the Flex Spending portlet using a querystring argument. When setting up a PTHTTPGETRequest, you’ll notice that the second argument is essentially a function pointer that allows this object to execute a callback when the response completes. All that callback function needs to do is place the content of the Flex Spending portlet into a div tag and you’re done.

I think Plumtree does a great job with all their Adaptive Portlet examples – you can literally copy and paste them into your portlet code and they just work. However, if you get stuck and need more help, feel free to post here or on portal.plumtree.com.

Backend System approach

So we’ve talked about how to pass a small piece of state from one portlet to another, covering the with-page-refresh and without-page-refresh cases in addition to the single-community/page and multiple-community/page case. But what about the case where your state is not quite as simple as a employee ID?

The first question I have to ask is, why are you trying to pass a lot of state? Isn’t the employee ID sufficient to go into the backend system and get whatever data you need? If the answer is no, then what form is your state in? Do you have a piece of text or an object? If you have a small piece of text, you can use either of the first two approaches: set it as a User Setting or URL-encode it and pass it around using Master-Detail or Broadcast-Listener. If you have a small object, you can serialize it and then Base-64 or UUEncode it and then use one of the first two approaches. But you need to be very careful. There are limits to the amount of data you can put on a querystring and limits to amount of data you can put in a header. These limits are not enforced by the HTTP spec, but the spec warns you about artificial limits on URL length based on web server implementations. Mark Nottingham, Senior Principal Technologist at BEA Systems, cautions against using headers larger than 2048 bytes in this post. Remember, all Plumtree Settings are passed back and forth between the portal and portlets as HTTP headers.

So you’re stuck with a somewhat bulky object, let’s say in our example, the entire employee’s record in a DTO, and so you’ve ruled out the first two approaches. Now what?

If you’re a traditional web programmer who’s new to Plumtree, you might have been thinking this all along – what about the HTTP session? Isn’t storing and passing state from page to page what sessions are for?

Sessions are great place for things like an employee record DTO, but in Plumtree, each portlet has its own session on the remote server. This means that you can put whatever you want in the session, but you’re not going to be able to share it with other portlets. Using the session also has interesting ramifications if you’re using Plumtree caching, but that’s the subject of another post.

So, what about the HTTP application? If you have a single remote server and all your portlets are using it, you can store objects, like the employee record DTO in the application, using a key consisting of the employee ID as follows (inside a Java servlet):


synchronized(this) {
this.getServletContext().setAttribute("com.bdgportals.iam.example.EmployeeRecordDTO" + employeeID, employeeRecordDTO);
}

Different portlets can now access this attribute, but you need to make sure that all your code that writes to this attribute is threadsafe.

Of course, this assumes that you’re using the same application server for all your portlets, which is not necessarily true, even for a single application (because you may be load-balancing your porltets across different application servers).

* * *

If there are other ways you’ve found to pass state between portlets, I’d love to hear about them via comments on this post.

Query filters explained, at last

I can’t even begin to count the number of times I’ve been asked how to write a query filter in Plumtree. Yesterday, I had to write one for myself and lo and behold, I was confused. I’ve come to the conclusion that they’re just hard to write. Despite this, they’re incredibly useful when trying to lookup objects in the Plumtree API.

(Note: this post does not apply to writing portlets or other integrations. It’s only useful when writing Pluggable Navigation, PEIs, or other customizations to the UI.)

To use a query filter, you’ll first need access to a Plumtree user’s session. Let’s assume that you have one in the variable plumtreeSession and that it’s already connected as a user who has at least read-level access to some objects. This query will work for any object, but just for the sake of example, let’s use Groups. Also, I wrote this in Java, but it works almost exactly the same way in C#.

First you need to get an IPTObjectManager as shown here:

IPTObjectManager groups = plumtreeSession.GetUserGroups();

Next, we’ll build up the query filter, which is always an Object[][].

Object[][] filter = new Object[3][1];
filter[0][0] = new Integer(PT_PROPIDS.PT_PROPID_NAME);
filter[1][0] = new Integer(PT_FILTEROPS.PT_FILTEROP_EQ_NOCASE);
filter[2][0] = "Everyone";

Let’s go through that line by line. First of all, why did I choose 3,1 for my array dimensions? All query filters are 2D arrays. The first dimension always has three items:

    1. The name of the property on which you’re filtering
    2. The operator (equals, less than, greater than, etc.)
    3. The value of the property you’re evaluating

Since it’s an Object[][], we can’t use primatives, so we must box our constants in Integer objects because the constants themselves are primatives.

When using the Query method that supports a query filter, you also need to specify an ordering attribute. You can only order ascending, but you can order by up to three properties which will be applied in the order they are put in the array, as shown below:

int[] orderBy = {PT_PROPIDS.PT_PROPID_NAME, PT_PROPIDS.PT_PROPID_OBJECTID};

In the code above, I’m asking to order first by name, then by object ID. (Since no two names can be the same in Plumtree, this dual ordering doesn’t really make much sense, but oh well.)

Now, finally, it’s time to run the query:

IPTQueryResult group = groups.Query(PT_PROPIDS.PT_PROPID_OBJECTID + PT_PROPIDS.PT_PROPID_NAME, -1, orderBy, 0, -1, filter);

Let’s break down those parameters one by one. The first, PT_PROPIDS.PT_PROPID_OBJECTID + PT_PROPIDS.PT_PROPID_NAME is a bitmask of properties you want to include in your results.

The second, -1, means query all folders in the admin directory. (If you want to restrict your query to a single folder (and all folders below it), use the folder id here. If you want to query down two distinct folder trees, you’ll need to run two queries.

The third, orderBy is your ordering attribute(s), explained above.

The fourth, 0 is your starting row.

The fifth, -1 is the number of rows to return (-1 means all rows). This parameter, along with the starting row, can be very useful for pagination.

The sixth and final parameter is your beloved query filter.

We did it! Now that wasn’t so bad, eh? Iterating through the results set is trivial, so I won’t cover it here, but if you have you have a question, feel free to make a comment here or post on the developer forums.