Everyone likes a friendly URL

As part of our BEA World strategy for this year, we’re revamping our corporate web site, http://www.bdg-online.com. You should expect an unveiling in the upcoming weeks.

While there will be some revised and some additional content, this is primarily an infrastructure upgrade, including moving to more powerful virtual hosts and upgrading the backend from ASP to ASP.NET (yes, I know, it’s about time).

One of things that really bugs me about ASP and ASP.NET is the failure to include built-in support for friendly URLs. By friendly I mean something that doesn’t end in .asp, .htm, .aspx or some other extension and naturally also doesn’t have a querystring (?foo=bar&boo=moo . . . etc.). For example, http://www.bdg-online.com/customers is a lot more friendly than http://www.bdg-online.com/customers.asp and definitely more friendly than something like http://www.bdg-online.com/content.aspx?p=/customers.

Java provides a nice facility for this in the form of servlet mappings. Since a lot of people are using MVC these days, you are probably going to set up servlet mappings anyway. Here’s an example from a sample web.xml file:



But what about ASP or ASP.NET? No one cares about ASP any more, so I didn’t bother to research that. But for .NET, I came up with a simple and elegant solution to the friendly URL problem. All you need to do is add the following code (or something like it) to your Global.asax.cs file:

protected void Application_BeginRequest(Object sender, EventArgs e)
 if (!Request.RawUrl.EndsWith("htm") &&
     !Request.RawUrl.EndsWith("css") &&
     !Request.RawUrl.EndsWith("ico") &&
     !Request.RawUrl.EndsWith("jpg") &&
     !Request.RawUrl.EndsWith("js") &&
   if ("".Equals(Request.RawUrl) || "/".Equals(Request.RawUrl))
     Context.Server.Transfer(Request.RawUrl + ".aspx");

You’ll note that I forward requests to the corresponding aspx page, as long as the request isn’t for static content (images, css, etc.).

Of course you also need to do two things:

  1. Configure an .aspx page for every friendly URL you want resolved
  2. Add a wildcard mapping in IIS for * (files without extensions) to the asp.net ISAPI filter

The process for #2 is a little involved. It’s also different for IIS 5 (XP) and IIS 6 (2003). I don’t feel like posting screen shots right now, but if anyone wants to give this a trial run and can’t figure out how to do #2, just e-mail me and I’ll walk you through it.

I just came up with this a couple of hours ago and I haven’t put it through much testing, so YMMV.

Caveat Emptor: Using Varpacks in Pluggable Navigation

I got burned by this today, so I thought I would share it with you all. I had a perfectly good and working pluggable navigation that loaded a remote portlet in the left navigation pane. The only problem was that I had hardcoded the portlet ID and I wanted to make it configurable. So naturally I put the portlet ID and some other settings in a varpack, which is a reasonable thing to do. I then called my varpack from the constructor of my pluggable navigation class that implements IView.

Then I spent the next hour banging my head against the keyboard.

I kept getting a nasty Invocation Target Exception coming out of the reflection methods used to pre-load pluggable navigations. Eventually, using the handy space=MemoryDebug trick, I was able to ascertain that my varpack XML syntax was wrong and my varpack was looking empty to ALUI. So I fixed that and still, I got an ITE.

Then I looked at a PTSpy log and I discovered that the loading order of objects in ALUI was to blame. The portal loads built-in varpacks first, then it loads pluggable navigations, then it loads custom varpacks. So you can’t use the varpack from the IView constructor. I moved it to the Display method and everything started working again. Phew. 😐

So, shame on me for trying to use a custom varpack before it was loaded. Make sure not to make the same mistake!

My take on the acquisition of Plumtree by BEA

Several colleagues, coworkers, customers and other Plumtree partners have asked me for my opinion on the buyout of Plumtree by BEA Systems. I certainly have thoughts and comments about this event, but moreover I have several open questions that I want to ask Plumtree, BEA and the community of customers and partners. Of course I have my own take on the answers, but I’m curious to hear from others in the community.

First, let me say this: I feel overwhelmingly positive about the acquisition. BEA is a great company with excellent products (Weblogic, Tuxedo, JRocket) and a solid strategic vision. Most of the articles I’ve read have said that they plan to make Plumtree its own business unit and continue to support Plumtree’s 700 customers. By purchasing Plumtree, BEA has made a strong, albeit implied, statement about the portal market. You won’t read this in any of the articles out there, but it’s a statement that I’ve been making for a long time: Plumtree is clearly the best and the only pure-play horizontal portal technology out there. All of this is good news for Plumtree and for Plumtree partners like bdg.

Now, on to my questions . . . .

Will BEA continue to support Plumtree on .NET?

According to the FAQ published on BEA’s web site, the company plans to support Plumtree on all of the existing platforms and application servers on which it runs. This is a major change of direction for BEA, which has always aligned itself more with the Java/Sun/McNealy vision that the .NET/MS/Gates vision and which ties all of its products to its own application server, Weblogic.

The problem is that IT departments in major companies have their own near-religious beliefs about platforms. Some want “pure” Microsoft stacks (Windows, SQLServer, IIS, .NET/CLR), some want “pure” Java stacks (Solaris, Oracle DB, Weblogic/Websphere/Tomcat/JBoss and Java/JVM) and some even want LAMP stacks (Linux, Apache, MySQL and PHP).

In order for a portal — the UI integration layer for the enterprise — to be successful in the heterogeneous IT world in which we live, it must run on all of those platforms and it must have a strategy for supporting integration with every platform. It’s clear from their product direction, including their recent decision to support Linux, that Plumtree has known this for a long time. I can’t speak for BEA, but the message I’ve been getting from them for the past several years is that you can solve all the world’s problems — or least all the world’s IT problems — with Java. As much as I like Java, I’ve never quite bought into that vision. The IT world is just too heterogeneous for that vision to approach reality.

I sincerely hope that BEA sticks to this new strategy of supporting the Microsoft stack for Plumtree. The good news is that Weblogic has always run on Windows. Running Java on Windows is fine in my book, but if you tell that to the approximately 500 Plumtree customers who run Plumtree on a Microsoft stack, they’re not going to be pleased. In fact, I think they’ll start looking for another solution, perhaps even Sharepoint.

What will happen to BEA’s Portal product?

The press releases are calling BEA’s portal product a transactional portal for the extranet and Plumtree’s a collaborative portal for the intranet. This is nothing more than an attempt to downplay the competitive nature of the two products. This spin isn’t working for me. bdg has built transactional extranets using Plumtree and I’m sure that enterprises have built collaborative intranets using the BEA Portal. In fact, BEA specifically pitches the collaborative features of their portal product as part of their marketing literature.

Obviously the companies need to make a statement saying that they’re going to support both camps in order to avoid massive customer hemorrhaging. (Look what happened to Epicentric’s customers when they were acquired by Vignette.) It’s good to hear that the near-term plan supports both portal products for the sake of the customers, but I hope to hear some more believable strategic direction from BEA and Plumtree about their clearly competitive portal offerings.

What would make sense to me would be a hybrid that includes most of Plumtree’s compelling out-of-the-box functionality — including collaboration, content management and usage tracking — and merge it with the compelling parts of BEA’s portal, such as the Portal Java Controls and the Portal Resources Designer. Development tools like these will greatly enhance Plumtree’s Java developer offerings to bring them up to speed with their Microsoft offerings (like the EDK’s .NET Web Controls). But there are some big architectural decisions to make. For example, is it better to integrate BEA’s Designer with the Plumtree EDK to help those of us building Java portlets, or should they take an IDE plug-in approach for Eclipse like Plumtree did with the .NET IDE?

The industry press is still beating up BEA for having a Java client portal designer instead of a web-based one just like they beat up Plumtree four years ago because of their Windows-based portal designer (called Content Manager). The answer is simple: BEA needs to webify their portal designer. But if they’re going to live by their new strategy of cross-platform support, anything they build will need to have a .NET equivalent.

This may be cynical, but I think telling all the developers who currently support Weblogic Portal that they’re going to have start thinking about portability to .NET is going to be a hard sell.

How will the merger affect the ship date for Plumtree G6?

Plumtree has set a ship date for G6, the next generation of their portal product. The product is currently in Beta, so we all know that we’re getting close.

The press releases and FAQ do not mention G6 or say anything about the next version of BEA’s portal. If any kind of tangible BEA Portal/Plumtree Portal integration attempts are squeezed into G6, I doubt that they will hit their ship date.

I think it would be a smart move to ship G6 as is — and there’s a good chance that it will happen, given the fact that Plumtree will be a separate business unit at BEA — and then shoot for integration in the next major product iteration, whenever that is.

I hope to hear some clear direction from the two companies on this soon because our customers’ rollout plans are directly affected by information like this.

Will this deal make BEA even more of an acquisition target for Oracle?

Everyone I know — myself included — had a feeling that Plumtree would be acquired some day. But the major questions were 1) when and 2) by whom? Quite some time ago and long before Plumtree had its Java strategy fleshed out, there were rumors of a Microsoft takeover. Then Siebel. Then Peoplesoft. But BEA? I never would have guessed.

I personally thought Oracle would be the suitor, especially after they acquired Oblix, PeopleSoft and J.D. Edwards. After extending its tentacles into almost every enterprise software market (and proving tremendously incapable of producing any decent software applications other than a database), Oracle snapped up ERP, HR and SSO/Identity Management in the blink of an eye. It seemed reasonable to me that a good portal product that could integrate with all those applications would be a clear next target. Oracle’s portal certainly doesn’t cut the mustard. In fact, they often offer it up for free only to be beaten out by Plumtree, which is, ahem, a far cry from free.

Now the next pressing question: is Oracle even more likely to acquire Plumtree now that they’re a part of BEA? Now they’d get an excellent application server and a cross-platform, industry-leading portal. You know it crossed Larry Ellison’s mind when he heard the news. Food for thought.

What will happen to the name Plumtree?

Back in late 1998, when BEA acquired WebLogic, Inc., they kept the company’s preexisting market share and mind share intact by transitioning the name of the company into the name of what has become BEA’s flagship product. Oracle has done the same with its recent acquisitions.

BEA would be wise to do the same with Plumtree. “BEA Plumtree Portal” may not have a ring to it right now — but mark my words — it is soon to become a household name in the world of enterprise software.

* * *

For all of you who asked, those are my thoughts on the merger. Sorry it took me almost a week to come up with a response to your questions, but if you recall from an earlier post, I was teaching a Plumtree training class all last week. Anyone who has taught training knows how exhausting that is, hence the delay in putting my thoughts on (virtual) paper.

As always, your comments are most welcome.

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:


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.