Sunday, November 16, 2008

ALUI / WebCenter Interaction: Introduction to Native API development (Part 1)

Most of the time, creating a remote portlet application using the standard IDK is enough. Indeed, commonly, you just need to access user profile information, portlet ID, page ID etc... or perform simple operations exposed by the IDK PRC API.

But if you hit the limits of the IDK, it is not the end of the road. In the ALUI/Webcenter development documentation, they explain how to perform various UI customizations such as view replacement, PEI development, Activity Spaces creation or extensions, etc... All these are created within the portal application itself...Another option is to create what I call a "Native API Portlet Application". As its name indicates, this portlet application accesses directly the portal API and can perform virtually any operation that the portal can do...very powerful (but non supported :) so make sure your application is well written so that you can change the portal API access layer easily if you upgrade the portal version for example)

First, the 2 main requirements in order to create a Native API application are:

  • The application needs to be on the same server as Portal, or Automation, or API service
  • The application needs to reference various portal DLLs (located in /ptportal/6.1/bin/assemblies for dotnet, or /ptportal/6.1/lib/java for java). You don’t need them all. Here is the minimum list:



    ptportal\6.1MP1\bin\assemblies\opencache.dll

    ptportal\6.1MP1\bin\assemblies\openconfig.dll

    ptportal\6.1MP1\bin\assemblies\opencounters.dll

    ptportal\6.1MP1\bin\assemblies\openfoundation.dll

    ptportal\6.1MP1\bin\assemblies\openhttp.dll

    ptportal\6.1MP1\bin\assemblies\openkernel.dll

    ptportal\6.1MP1\bin\assemblies\openkernelsearch.dll

    ptportal\6.1MP1\bin\assemblies\openkernelsearchimpl.dll

    ptportal\6.1MP1\bin\assemblies\openlog-framework.dll

    ptportal\6.1MP1\bin\assemblies\openprocman.dll

    ptportal\6.1MP1\bin\assemblies\opensharedcache.dll

    ptportal\6.1MP1\bin\assemblies\opentempfile.dll

    ptportal\6.1MP1\bin\assemblies\openusage.dll

    ptportal\6.1MP1\bin\assemblies\openusage-api.dll

    ptportal\6.1MP1\bin\assemblies\openusage-impl.dll

    ptportal\6.1MP1\bin\assemblies\plumtreeserver.dll

    ptportal\6.1MP1\bin\assemblies\portal.dll

    ptportal\6.1MP1\bin\assemblies\pthome.dll

    ptportal\6.1MP1\bin\assemblies\ptportalobjects.dll

Important note: It is perfectly allowed to also include the IDK Dlls here too... and I find it particularly recommended if you are writing a native API portlet (for instance getting the current login token for example is fairly easy using the IDK API)

Second, you need to create the native session (everything starts from here, really):

1: String strServerConfigDir = ConfigPathResolver.GetOpenConfigPath(); 
2: IOKContext configContext = OKConfigFactory.createInstance(strServerConfigDir,"portal");
3: PortalObjectsFactory.Init(configContext);
4: IPTSession ptsession = PortalObjectsFactory.CreateSession();

From there you actually need to connect this session with a particular user identity. That way, the session object will be aware of your identity and especially the security and permission associated with your identity. In other words, even if you are using the native API, you cannot do more than you are allowed to.

To connect, 2 main options:

  • Use the login token that you can simply get from the IDK API (that is prefered option if you can)
1: String loginToken = m_portletRequest.GetLoginToken(); //IDK call
2: ptsession.Reconnect(loginToken);
  • Use explicit Username (or user ID) / Password to connect.

1: String username = "myusername";
2: String pwd = "mypassword";
3: ptsession.Connect(username, pwd, null);

Third (and Final), you access the right ObjectManager Class depending on which type of portal object you want to interact with.

When the session is created (that was pretty easy, right?), that is when you can actually start interacting with the portal internals...and a majority of actions goes through the PTObjectManager objects (IPTObjectManager interface). For instance:

1: IPTCommunityManager ptCommManager = ptSession.GetCommunities(); //for community objects
2: IPTPageManager ptPageManager = ptSession.GetPages(); //for community page objects
3: IPTObjectManager ptGadgetManager = ptSession.GetGadgets(); //for portlet objects
4: //etc...

You noticed that for portlets, there is not a IPTGadgetManager insterface....that’s ok as all the "Manager" interfaces are children of the base IPTObjectManager interface.

Although the vast majority of manager objects are accessible through a direct ptsession.Get() call, you can also get the right manager using the generic call below (using the classID of the object type you want)

1: IPTObjectManager ptCrawlerManager = ptSession.GetObjectManagers(PT_CLASSIDS.PT_CRAWLER_ID); 
2: //using     the class id of the object type you want

From there, the freedom is yours... and various operations will be available depending on the manager you called. One call for instance that all managers have is the open object:
1: ptObjectManager.Open(objectid, lockObject);

With this call, you get directly access a particular object in the portal, and interact with it as if you were in the UI

In the next article, I will show you how I package these API call in a standalone library to minimize as much as possible any API call within the presentation layer code...

Monday, October 27, 2008

ALUI Publisher - Part 3: No Redirect Bug Fix of Bug Fix :)

I have been relatively lazy in regards of my blog lately, and I have plenty of articles that are stacking up...But in the meantime, I thought this one is pretty urgent.

In one of my previous article, ALUI Publisher - Part 2: Increase Performance by enabling REAL Caching - No Redirect Bug Fix, I was explaining how to fix the Publisher published_content_noredirect.jsp (see  in that serie the benefits of using this instead of published_content_redirect.jsp).

Well, I found out a small little bug on my part, and it is definitely worth fixing if you have not done so already. In my corrective code, I was trimming the content string from its end spaces (just to optimized the HTML output)...and I did not think of the likely negative effects, such as if the buffered content does finish on a meaningful space character (such as a sentence separator etc...)

So the updated code with bug fix is: (specifically the trim that is removed)

//if there is content, forward to the requesting client
int buffersize = 2000;
int charread = 0;
char[] content;

//read until no byte is found in the input stream because request content length is no reliable
// UTF-8 is necessary
BufferedReader bisr = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

do {
content = new char[buffersize];
charread = bisr.read(content);
out.write(new String(content).trim());
} while(charread > -1);

bisr.close();
bisr = null;
content = null;


Better to find it late than never! :)

The code should be updated on the famous (yeah right...) ALUI Toolbox Google project (or should be soon)

So Long.

Sunday, September 28, 2008

ALUI Enhancement: Get/Set All Preferences from Javascript

As you probably already know, ALUI Portal personalization features are mostly guarantied by the possibility of setting/getting "preferences" with various scopes. Not to myself extend too much on this concept, you can refer to the ALUI Development Documentation (Link HERE) to have further explanations. While you read this documentation, you'll learn that preferences can be set and retrieved through:

  • the IDK API (most commonly),
  • the server API (much less common since Server API should mostly be used only if the IDK cannot fulfill your needs), or
  • the Javascript API (but only for preferences of scope "session")

What is usually done consists in building a JAVA or Dotnet application that uses the IDK API to get/set preferences within a portlet, allowing for the presentation or behavior of the portlet to change based on the preference chosen.

But as you build ALUI intranet or even Internet websites, you often realize that most of the portlets are either content-specific with some kind of personalization (i.e. a link showing only if this preference has been set for that user...), or have a pretty simple behavior and presentation.

Would not that be cool to be able to use "Publisher" for example to build those simple portlets? In most cases, with the power of the ALUI Portal Adaptive Tags coupled with the Publisher PCS Tags (this could apply to any other Web Content Management Systems, but why not use Publisher as an example since it is still alive :) ), you could build such simple portlets without the need for programming a portlet in JAVA or Dotnet...

But what about preferences? How could you set and get preferences, since they are available only through an API that can be used only using those programming languages? Well, ALUI has already thought it through, and integrated within their Javascript API the possibility to set/get "Session" preferences. That was great thinking indeed. But I kept (and still keep) asking myself: Why having developed this idea only half way through?? Why allowing to only set/get "Session" preferences through Javascript? All I know is that there is no reason why not...and I just wanted to share this essential feature.

Javascript Session preference: How does this work?

So first, let's understand how the Javascript preference access works. Basically an activity space has been developed and its code is found in the following package: com.plumtree.portalpages.browsing.sessionprefs. As the portal follows a strict MVC (Model View Controller) architecture, an activity space is mostly composed of a "Control" class (implementing IControl interface), a "Model" Class (implementing IModel interface) and a "Presentation" class (implenting IDisplayPage interface). You can refer to the "ALUI Portal Customization Package" to see the code of this sessionPrefs activity space. To request the activity space functionnality, simply create a HTTP request with the right parameters, like this:

http://your.host.domain.com/portal/server.pt?space=SessionPrefs&control=SessionPrefs&action=getprefs&_preferencename=

http://your.host.domain.com/portal/server.pt?space=SessionPrefs&control=SessionPrefs&action=setprefs&_preferencename=preferencervalue

From there, all there is to do is to allow that request to be called from Javascript, through an AJAX HTTPWebRequest...The javascript methods getSession() and SetSession() which initiate that AJAX HTTPWebRequest will use the PTPortalContext javascript object defined on every page to get the right ActivitySpace url as follows:

PTPortalContext.GET_SESSION_PREFS_URL = 'http://localhost/portal/server.pt?space=SessionPrefs&control=SessionPrefs&action=getprefs';
PTPortalContext.SET_SESSION_PREFS_URL = 'http://localhost/portal/server.pt?space=SessionPrefs&control=SessionPrefs&action=setprefs';

...and that's it...Plumtree/BEA delivered your ALUI Javascript-Enabled "Session" Preference behavior.

Javascript preference of "All Type": How does this work?

All I did was extending on this principle in order to make all type of preferences available through Javascript, and as you understood now, through the behind-the-scene Preference Activity Space. Since I post the code on "ALUI Toolbox Google Project", I will pass on the very details of the code...

The main outline is:

  • Create a new Activity Space called "PortalPrefs" instead of SessionPrefs
  • Update the PortalPrefControl class to take into account a new parameter "type" which allow user to specify the type of preference you want to get/set (possible values are: portlet, admin, session, user, community, communityportlet).
  • Update the PortalPrefsModel class with the corresponding Preference Getter/Setter methods for each preference type (or scope)

Now, after installing this new code, the urls to access the AS are (differences in bold)

http://your.host.domain.com/portal/server.pt?space=PortalPrefs&control=PortalPrefs&action=getprefs&type=PreferenceType&_preferencename=

http://your.host.domain.com/portal/server.pt?space=PortalPrefs&control=PortalPrefs&action=setprefs&type=PreferenceType&_preferencename=preferencervalue

Then you have the choice as far as Javascript is concerned: either you create your own layer that performs the call to this new activity space, or you plug this new bahavior into the already existing Javascript framework, without any modification to the framework itself.

I personally chose the later, since I always try not to modify the portal existing libraries (just to allow for easier future upgrades of those libraries). All you have to do is to make sure to override on your portal page the PTPortalContext URL properties with the new AS URL end point BEFORE you call the already existing GetSession()/SetSession() javascript methods. To do that, you could simply create the following Facade JS methods to be called from your portlets:

<Script>

GetPortalPreference(prefType, prefname){

PTPortalContext.GET_SESSION_PREFS_URL = 'http://your.host.domain.com/portal/server.pt?space=PortalPrefs&control=PortalPrefs&action=getprefs&type=' + prefType;

GetSession(prefname); (this is the call to the already existing JS framework for session preference)

}

SetPortalPreference(prefType, prefname, prefvalue){

PTPortalContext.SET_SESSION_PREFS_URL = 'http://your.host.domain.com/portal/server.pt?space=PortalPrefs&control=PortalPrefs&action=setprefs&type=' + prefType;

SetSession(prefname); (this is the call to the already existing JS framework for session preference)

}

</script>

That's it! Feel free to browse the code (only JAVA version for now) at the Google Code Project I created (I also created for you the JAR that contains this code...that way, you can easily install and test this on your portal) and please let me know your thoughts! Hopefully, this will be integrated in the future releases of ALUI.

Monday, August 4, 2008

ALUI Best Practice - Don't Hardcode ObjectIDs: Use UUIDs Instead

In ALUI, there are 2 ways to identify uniquely an object:

  • ClassID (the type of object) + ObjectID (The ID of the object within the classID family)
  • Global UUID (unique ID throughout the environment)

The ClassID/ObjectID combination is used throughout the Portal API to query/open/manage the ALUI objects, as well as navigate to communities and pages. The ALUI ADAPTIVE TAGS are no exception: you will notice that they require ObjectID / ClassID to perform their tasks, like for example the opener tag:

<pt:standard.openerlink pt:objectid="219" pt:classid="514" pt:mode="2" target="myWindow">view community page</pt:standard.openerlink>

The main problem is not in the fact the ObjectID / ClassID is a bad way to identify an object, but in the fact that the ObjectID WILL NOT NECESSARILY (very improbable actually) be the same when you migrate objects from one environment to another. And that's where it can hurt...

Indeed good practice is to test out your creation in DEV / TEST / STAGING etc... and then migrate it using the ALUI migration tool. Since objectIDs will be different after migration in the new environment, all the objectIDs used in Adaptive Tags will have to be changed...hassle indeed.

Fortunately, UUID does NOT change with migration (or very improbable) from environments to environments. So that would seem a good option if you need to hardcode IDs, especially in Adaptive Tags, and I'd recommend that option everywhere you can.

In order to make it possible, I built a Adaptive Tags that does just this: Transform a UUID into its corresponding ClassID/ObjectID pair. All you need to do is use that Adaptive Tag before using the opener link tag for example. The object and class IDs are stored in shared memory (adaptive tag framework) with the specified scope and can be reused with any other tags that require objectID / ClassID.

<pt:taglibname.convertuuidtoid pt:uuid="{UUID}" pt:objectid="objectIDKey1" pt:classid="classIDKey1" pt:scope="portlet request" />

<pt:standard.openerlink pt:objectid="$objectIDKey1" pt:classid="$classIDKey1" pt:mode="2" target="myWindow">view community page</pt:standard.openerlink>

What's even better is that you can use this tag even for your remote portlet applications, like any other tags.

The code to change a UUID to the ObjectID / ClassID pair is fairly simple. Just get the Migration manager and call the convert method UUIDToObjectID to get the job done. I created a helper method that package it altogether:

public Object[] getClassObjectID(String uuid){
        Object[] oClassIDObjectID = null;
        if (null != uuid) {
            try {
                IPTMigrationManager oPTMigrationMgr = (IPTMigrationManager) oPTSession
                        .OpenGlobalObject(
                                PT_GLOBALOBJECTS.PT_GLOBAL_MIGRATION_MANAGER,
                                false);
                oClassIDObjectID = oPTMigrationMgr.UUIDToObjectID(uuid);
            } catch (Exception exc) {
                oClassIDObjectID = null;
            }
        }
        return oClassIDObjectID;
    }

The first item in the returned array is the ClassID (oClassIDObjectID[0]), the second item is the object ID (oClassIDObjectID[1]).

You can download the code on my newly created subversion project (http://alui-toolbox.googlecode.com) on Google code (I'll be updating/maintaining this as I see fit - feel free to suggest at will :)):

svn checkout http://alui-toolbox.googlecode.com/svn/trunk/ alui-toolbox-read-only

No more mocking around with IDs during migration :)

Hope that helps!

Wednesday, July 23, 2008

Inside ALUI Grid Search: Redundancy Bug (6.1 on window at least)

With ALUI 6.1, BEA introduced a completely revamped search component for ALUI, allowing for better redundancy and better throughput: Grid Search. The main advantages of that new search component are:

  • Multiple search nodes to provide redundancy for serving search requests.
  • Search index can be split in multiple partitions, each attached to various search nodes., to increase throughput.

Every nodes on the same partition automatically replicate locally their search index to guaranty redundancy and performance.

Although there is capability for multiple nodes that guaranty redundancy, all the nodes need to access a central "cluster" data repository located somewhere on the network (through file share). It is located by default at <ALUI_HOME>/ptsearchserver/6.1/cluster. What is usually done is to share that folder (simple network share if you are on windows) and set up the other nodes to access that share as their cluster repository. This cluster repository holds the cluster information (nodes and partitions info) and the multiple search checkpoints that allow for search index backup.

One main problem that I personally experienced with that design consists in the fact that this cluster repository represent a single point of failure... if the cluster share is suddenly not available (hard disk, server, or network failure), all the nodes are not able to talk to the cluster and there might be problems happening.

And actually, a huge problem occurs in that case: if the cluster share is not available, all the nodes are suddenly experiencing an "Out Of Memory" exception and shutting down abruptly. Thus, although you deployed multiple nodes and partitions, if the cluster share is down, your search architecture is...down.

It is pretty easy to test (at least I successfully reproduced the bug on ALUI 6.1 MP1 Patch 1 on windows server 2003): have your nodes all running, and simply remove the share from your cluster folder...all your nodes will go down (apart from the one that accesses the share locally if the cluster share is installed on the same server as one of the nodes)

2 options from there:

  • make sure the share is never down (windows clustering, redundant NAS cluster, or polyserve technologies)
  • install that critical fix from BEA that fixes this bug

If you don't have an infrastructure that provides the first expensive option, you might want to look seriously into the 2nd one...and contact your sales rep asap. Basically, the critical fix allow for the nodes to continue serving requests even if the cluster share is no longer available. All the nodes switch automatically in read only mode without the "out of memory" exception that was occurring before.

Although it is much better, some problems are still present with that critical fix. When in read-only mode, the nodes are no longer indexing new content...your search index is then blocked at the point in time when the cluster share did actually go down, and any new object or document will not show up in the search as long as the cluster share is not restored. The second problem is that the nodes will NOT automatically roll back to read/write mode whenever the cluster is available again. It will require a manual restart.

But compared to a total shut down of search, these problems seem less important indeed!

I am not 100% sure this fix has been pushed to ALUI 6.5 but I sure hope so. And by fix, I am talking about a total fix including auto rollback to "normal" mode when share is available anew, or even allowing for TOTAL continuity of service when this share goes down...

Please let me know (leave comment) if you have that information on 6.5, or if you reproduce this with other versions of the portal.

Tuesday, July 15, 2008

ALUI Tool: URL (or text) Migration within Publisher Items

Following my previous article "ALUI Administration Tool for Environment Refresh: String Replacing for URLS" talking about migration between environments, here is an extra piece that you might find very useful (I surely use it all the time)

Basically, as explained in the previous article, it is common to have different DNS aliases set up per environment...I.e for publisher remote server, you could have:

Similarly, the publish browsing URL is not an exception to this rule:

  • http://publisher-content.domain.com/publish  for production
  • http://publisher-content-stg.domain.com/publish for staging
  • http://publisher-content-dev.domain.com/publish for development
  • When you add an image or a link in the free text editor of content items in publisher, it will most of the time create an absolute URL to that resource...thus you can imagine that there will be a lot of DNS aliases within a lot of publisher items throughout the environment.

    What happen when you migrate the publisher DB from one environment to another? Well you will have a lot of DEV dns aliases within your Staging environment (in case of a DEV promotion to Stage); or a lot of production DNS aliases within your dev environment in the case of a production refresh to DEV.

    In my previous article "ALUI Administration Tool for Environment Refresh: String Replacing for URLS", I was mostly talking about migrating URL within portal objects, but nothing really about migrating urls within publisher items.

    Thus, I created some DB scripts (SQL Server only for now) that do just that...

    1. puburls-PTCSDIRECTORY-nvarchar-replace.sql: Script to change a particular string within the PUBLISHEDTRANSFERURL and PUBLISHEDURL columns (which is mapped out in the DB to a column of type VARCHAR)
    2. puburls-PTCSVALUE-ntext-replace.sql and puburls-PTCSVALUEA-ntext-replace.sql: Scripts to change a particular string within the "long text" property of a publisher item (which is mapped out in the DB to a column of type TEXT)
      1. PCSVALUES.LONGVALUE (hosting the long text of the currently published item)
      2. PCSVALUESA.LONGVALUE (hosting the long text values of all the previous versions of the item)

    For the first script, PUBLISHEDTRANSFERURL and PUBLISHEDURL columns are of type VARCHAR and thus it is easy to replace a string within those columns using the REPLACE MS SQL Function. Thus, a simple SQL statement is good here.

    The main challenge was really with the 2nd scripts...indeed, within a column of type TEXT, the SQL "REPLACE" function cannot be used...The workaround is to use the PATINDEX and UPDATETEXT functions within a Transact-SQL (T-SQL) script. To give the credit to to the right person, I adapted a script that I found at ASP FAQ - How do I handle REPLACE() within an NTEXT column in SQL Server?

    DISCLAIMER: ALTHOUGH I PERSONNALY USE THIS SCRIPT ALL THE TIME, THERE IS NO GUARANTY; SO USE THIS TOOL AT YOUR OWN RISK blah blah blah AND USE IT ONLY IF YOU ARE PROFFICIENT ENOUGH WITH ALUI PORTAL TECHNOLOGIES.

    Attached is the zip file package that contains the 3 scripts:

    Don't forget to change the string to look for, and the string to replace it with

    puburls-PTCSDIRECTORY-nvarchar-replace.sql

    UPDATE [dbo].[PCSDIRECTORY]
    SET
    [PUBLISHEDTRANSFERURL]=REPLACE([PUBLISHEDTRANSFERURL],'-DEV.DOMAIN.COM','-TST.DOMAIN.COM'),
    [PUBLISHEDURL]=REPLACE([PUBLISHEDURL],'-DEV.DOMAIN.COM','-TST.DOMAIN.COM')
    WHERE
    publishedtransferurl like '%-DEV.DOMAIN.COM%'
    or publishedurl like '%-DEV.DOMAIN.COM%'



    puburls-PTCSVALUE-ntext-replace.sql and puburls-PTCSVALUEA-ntext-replace.sql



    SET @oldString = N'por-pubcontent-dev.domain.com'; -- remove N 
    SET @newString = N'por-pubcontent-tst.domain.com'; -- remove N


    That's it! Let me know if you find it as useful as I do! Enjoy!!

    Monday, June 30, 2008

    ALUI Publisher - Part 2: Increase Performance by enabling REAL Caching - No Redirect Bug Fix

    Previously (http://fsanglier.blogspot.com/2008/06/alui-publisher-part-2-increase.html) , I've been talking (and proving I hope) that using a "no redirect" mechanism for serving published content from publisher is the best option to enable portal caching. Publisher 6.4 offers already such a possibility (although not publicized a lot): using in the portal Published Content Web Service object published_content_noredirect.jsp instead of the standard published_content_redirect.jsp.

    Unfortunately, if you start using this, you are going to start seeing a weird behavior: the publish content is getting truncated in some special cases...and this is due to the way the JSP has been coded. Several options for you: either you wait for a Critical fix to be issued to you by BEA (i am not aware of one yet), or you upgrade to ALUI 6.5 (I hear that this has been fixed in 6.5...have not verified though), or you simply do it yourself, as this is a simple fix to implement (ultimately, that might be the same type of code that would be issued by a CF I imagine)

    By looking at the JSP within the publisher web application archive (ptcs.war - explode the war using jar command), we can see what's wrong and why the content is truncated in some case:

    HttpURLConnection conn = (HttpURLConnection)url.openConnection();

    // make the request
    conn.connect();

    //read the content length
    int contentLength = conn.getContentLength();

    //if there is content, forward to the requesting client
    if( contentLength > 0 ){
    // UTF-8 is necessary
    InputStreamReader isr = new InputStreamReader(conn.getInputStream(), "UTF-8");
    char[] content = new char[contentLength];
    isr.read(content);
    isr.close();
    out.write(content);
    }


    As you can see, an HTTP GET request is made, and the content length of the response is gotten from the "getContentLength()" method. This call is going to get the content length number fro mthe response header rather than actually count all the bytes that are contained in the response content. Thus, since the code base itself on this number to output the content to the JSP output stream (see above: char array of length equal to contentlength), the content will indeed be truncated if the contentlength number is not correct...



    A simple correction (and more robust code) is actually to make sure ALL the content is pushed to the output stream, independently from the contentlength number returned by the response header. Here is my code below that fixes that issue, and also increase performance by using the preferred BufferedReader wrapper class instead of the bare InputStreamReader:




    ------EDITED 3/12/2009--------
    BufferedReader bisr = null;
    try {
    bisr = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
    String line;
    while ( (line = bisr.readLine( ) ) != null ) {
    out.println(line);
    }
    }
    catch(Exception exc){
    throw exc; //to be caught by the global try catch
    } finally {
    if(bisr != null)
    bisr.close();
    bisr = null;
    }
    return;
    ------END EDITED 3/12/2009--------

    Basically, the code will read by chunks of 2000 chars (this is a chunk size that I think is appropriate) the entirety of the content until the last character...and write it all to the output stream...This does not rely on the contentlength at all, and thus is more reliable and robust.



    After changing the published_content_noredirect.jsp as above, you can repackage the ptcs.war with the new corrected JSP (within the root of the previously extracted ptcs.war folder, run jar -cvf ptcs.war * command) and redeploy to ALL redirector and publisher instances...



    Voila, you have your perfect solution for ALUI 6.1 and Publisher 6.4 (and previous versions too).

    ALUI Publisher - Part 2: Increase Performance by enabling REAL Caching

    In my previous post http://fsanglier.blogspot.com/2008/02/alui-publisher-increase-performance.html(man, already couple of month ago...I know I've been sucked into a black hole since then :) ) I was talking about how to best design a scalable and redundant ALUI Publisher architecture. But what I had not pushed enough in the last article was performance.

    In my opinion, the Publisher standard behavior for serving content has some performance flaw (at least in ALUI 6.1 - Publisher 6.4) related to caching... Since there are ways around this (that's what we do, right?), I think you might benefit from this a lot, and in my last implementation, the change explained below increased performance under load to complete new levels (in the meantime reducing DB requests and DB and publisher redirector CPU utilization)...So here it goes...

    As I explained in previous post, each published content portlet within a portal page are going to make a request to the Publish Content Redirector component, and particularly the JSP page in charge of performing the redirect: published_content_redirect.jsp (you can see that defined in the Published Content portal web service object). As the name says, this Java Server Page (JSP) performs a 302 redirect to the published content item (as seen in previous post, this location should be served by your favorite web server, apache or IIS for example...). But BEFORE making this redirect, it must know where to redirect to... so for that, the code makes a DB request to the publisher Database in order to get the browsing path to the published content item (passing the publisher content item ID that was saved when you created your published content portlet earlier).

    Ok so here is the first flaw I was taking about in previous paragraph: To be able to see some content through the publisher portlets within the portal page, you can see from the above explanation that multiple calls to the publisher DB will be made. Let's say we have 5 publisher portlets on the page (not uncommon), for each page rendering for 1 user, 5 DB calls will be made to the publisher DB (in addition of multiple other DB calls for portal and analytics). If we are now talking about thousands of users, we are talking about too many DB calls to simply see some content that does not change often. This has an unnecessary impact on DB load of your infrastructure, and will increase the page load consequently since DB calls are inherently slower that simple content rendering...

    While reading, some of view are already thinking for a good reason: CACHING! Yeah, indeed, caching is the secret to scaling and performance (not always necessary to take out the big bucks and supercharge even more the DB infrastructure). And great for us, the portal offers a great out-of-the-box caching capability within the web service object: simply set the minimum caching to 2 hours, max to 20 days, and normally, you would think that the portal should simply cache the published content for that amount of time...removing the need to call the published_content_redirect.jsp altogether, and thus the need to make a DB call!! ...but it does not happen this way. You don't believe me? Enable access logging on publish content redirector components (un-comment "Access logger" section within <ALUI HOME>\ptcs\6.4\container\deploy\jbossweb-tomcat50.sar\server.xml) and you will clearly see that even though your page contains only published content portlets that should be cached, the published_content_redirect.jsp  is still constantly called...and thus caching is not really....caching.

    Why does this happen? It is because of the redirect mechanism for serving content...From www.w3.org, 302 is explained this way: "The requested resource resides temporarily under a different URI. Since the redirection might be altered on occasion, the client SHOULD continue to use the Request-URI for future requests. This response is only cacheable if indicated by a Cache-Control or Expires header field." Thus, the portal is doing is job perfectly (it acts as a client here) and will never cache a response with a temporary redirect 302 status code.

    Ok so what can make it better? Changing the redirect mechanism to something that does not redirect...Well, using this other JSP actually already present and developed within ALUI 6.4 (I have not verified if present in earlier versions of publisher): published_content_noredirect.jsp. Instead of issuing a redirect to the published content, this jsp performs an HTTPGetRequest to it and write its content to the JSP output stream. The response code is now a simple 200 OK ("The request has succeeded" - www.w3.org) that can be cached by the portal. To enable this, simply change the HTTP url of the Published Content Web Service Object to be published_content_noredirect.jsp instead of published_content_redirect.jsp. Of course, check out the publisher redirector access logs to see the dramatic difference...under load, you will initially see a bunch of requests to published_content_noredirect.jsp, but very very fast, the access log becomes silent, all the content being really cached by portal...

    Result?? You can increase the load even more, and the page response satys the same (or is even better), and the DB utilization is not altered by that load...you simply have a site that is so much more performant. Our initial results showed that under constant intensive load (with and without the change) the publisher infrastructure would not crash anymore, the CPU usage of both DB and publisher redirectors would be consequently diminished, the number of DB requests would drop, and the load could actually be increased to new levels without loss of performance and functionality, thanks to caching.

    Since this post is already long, I am going to stop here for now...Please read next post (http://fsanglier.blogspot.com/2008/06/alui-publisher-part-2-increase_30.html) to understand the second flaw: the published_content_noredirect.jsp has a truncation bug...that is fixable of course :)

    So long!

    Tuesday, February 26, 2008

    ALUI Publisher: Increase Performance, Scalability and Availability

    ALUI publisher is the component that provides out of the box Web Content Management for the ALUI portal. Depending on the nature of your portal, Publisher can be an important or even critical part of your portal infrastructure (ALUI-powered Internet sites for example, or intranet with a lot of static content displayed through portlets).

    So if this component is really critical, the architecture design for that component must provide performance, scalability and redundancy. This article is meant to show you how to design Publisher Architecture to maximize performance, scalability and redundancy, and ultimately provide the best experience to the end user.

    Published Content portlets - How it works:

    First, let's lay out all the key components and understand the request flow for each Publish Content Portlet on a single portal page:

       PubContentRequestFlow_thumb_1

    It is important to reiterate that this flow is not per portal page, but per portlet. In other words, a portal page with 4 published content portlets will initiate 4 simultaneous request flows like the one above. From that, you can understand that depending on the load of these portal pages, the number of requests to the redirector and the publish content services could easily skyrocket, which is a strong proponent of clustering these components.

    The redirector, as its name states, will simply redirect the request to the right content url, based on the content ID that is given. Since this component actually makes more intensive DB calls and is accessed for every pub content requests (when content is not cached by the portlet of course), we definitely would want to cluster it and allow for future addition to that cluster when the load increase.

    The published content piece is a very simple "static web content serving solution". Although JBOSS or any other application servers are able to serve static content, none are as performant as true web servers optimized for the task: Amongst others, Apache or IIS are good possibilities.

    The problems:

    The main problem consist in the fact that the installer does not provide any tip to help you achieve that. By default, Publisher installer provides 2 options: Full Component (it means publisher engine, workflow engine, and the embedded redirector) or Publish Content Redirector Only.

    A couple of common shortfall if out of box design is followed:

    • Publisher engine (explorer) cannot be clustered.
    • Publisher internal application server (JBOSS) is serving publisher, workflow, redirection, and published content.
    • Publish Content Redirector standalone is not optimized for serving static content (it is used mainly to redirect to the actual publish content url, based on the requested publisher item ID)

    The Solutions:

    Ultimately, what we want to do is decouple each component from each other in order to scale it independently from the others. Thus, what we want to improve through architecture design consist in:

    • Publisher and workflow engine set up in failover mode. (Hot-Warm or Hot-Cold failover)
    • Publish Content Redirector Load balanced using Hardware (F5 BigIP, Cisco LB) or software load balancer.
    • Publish Content Served by appropriate web server (apache or IIS), optimized to best deliver static content (best performance)...instead of the publisher internal jboss app server (better optimized for dynamic J2EE content delivery).
    • Publish Content Web Server (apache or IIS) to be load balanced using Hardware (F5 BigIP, Cisco LB) or software load balancer.

    Following that design, the redirector can be scaled independently from the publish content serving mechanism, as well as from the publisher admin. And also, if the server that hosts publisher is down, the redirector services and publish content services are still able to provide content without any problem. Similarly, since the redirectors and pub content web servers are load balanced, they are fully redundant, providing maximum availability of static content on your ALUI powered internet site for example.

    So how do we tie everything together? Here is an overview of tasks that corresponds to what we talked about until now: (here using 4 servers in my example...could use more or less depending on what hardware is available to you...with a minimum of 2 servers of course.)

    1. Install full Publisher on Server A (contains redirector capability by default)
    2. Import the publisher objects in the portal (pte file)
    3. Install redirector component on Server B
    4. Install Apache/IIS on server C and D
    5. Create the 3 load balancing pools, 1 for Publisher (useful for HOT-WARM failover), 1 for Redirector, 1 for publish content web server.
    6. In publisher explorer, set the "publishing target" to a fault tolerant and fully redundant file share. (clustered NAS for example)
    7. Still in "publishing target" screen, set the browsing url to make sure it access the publish content web server pool (and as such access the Apache/IIS web servers)
    8. Setup Apache/IIS web servers on C and D in order to expose the published content that is at the "publishing target" set up previously
    9. We need to modify the publisher portal objects in order to make them access the correct load balancing pools
      1. Change PubContent Web Service Url to make it access the redirector load balancing pool.
      2. Also, change accordingly the gateway prefixes of the PubContent Web Service, especially the ones related to published content (publish/preview)
      3. Make sure the publisher url is actually going to the LB instead of going directly to publisher.

    One last thing you might want to do to still increase performance: Make sure you publish the images to the image server instead of the publish content repository. (Since the image server is publicly accessible from the internet, do this only if the images you are working with are not exposing information that should not be publicly accessible!). This is explained by the fact that serving binary content through the portal gateway component is much slower than serving the content directly to end user.

    Et Voila! When you are done configuring all that, you have a publisher infrastructure that is completely redundant in every aspects, offers maximum scalability for each critical components, as well as  maximum performance for serving static content.

    Monday, January 28, 2008

    ALUI Administration Tool for Environment Refresh: String Replacing for URLS

    Any company that owns a portal infrastructure such as ALUI will usually also plan for extra portal environments for troubleshooting and test purposes. Any portlet developments, portal customizations, or administrative changes will be implemented and tested in those environments. This is very good practice indeed. But you will quickly notice something happening: Your production portal is no longer in sync with your other staging / QA / Test environments. Although not necessarily a huge deal in the immediate future, that could become a problem when your test environment is really too different from the production one: Imagine the test team trying to execute a test plan in Staging environment, but half the production communities are simply not present in the test environment...etc...etc...etc...

    I am sure you figured where I am going: Sooner or later, a clean refresh of your tests environments will be needed. Such a refresh is best done by a full database copy from production to your test environment (ALUI built-in export / import functionality is not suited for a large amount of objects, and thus is totally inappropriate and not recommended in the present case)   

    Besides restoring all the appropriate repositories (documents, published content, search indexes etc...), a major problem remains: All the various service' urls specified in the various ALUI objects (Remote servers, web services, KD cards, server urls, etc...) are no longer accurate in the refreshed test environments (of course: those urls are the production ones). Thus  your test environment is far from working yet.

    2 possibilities from here (1 good and 1 less good):

    • You use host files in your test environments. These hosts files will direct the same production urls to the appropriate test servers (not good in my point of view because it is dangerous: if the hosts files is removed, there is a huge risk of having your test environment accessing production - thus not good :) )
    • You use environment-specific DNS entries for each services. (Much better because no risk of inter-environment communication)

    First, it is much better practice to call each service through DNS name rather than directly to through the server name. And secondly, it makes it much easier when it comes to environment refresh.

    Why? Because all the DNS entries follow a global "intelligent" pattern (i.e. PUBLISHER.COMPANY.COM / PUBLISHER-TEST.COMPANY.COM / PUBLISHER-DEV.COMPANY.COM / etc...), it is much easier to create a tool (or a DB query for those DB gurus out there) that will allow for automatic replace of these DNS names.

    That's where I wanted to lead you:

    I created a tool that allow just that: for all the portal objects that contain URLs, the tool can replace a specific pattern with another one that you define. Although I could have created a set of DB queries that could do the job (I actually started to do that when I had to do my first environment refresh), I realized that a utility written in JAVA (most portable language) and using ALUI server API would guaranty portability, extensibility and reusability. The main advantage is that it is completely independent from backend technologies, and can work with any ALUI portal (.NET or JAVA), as well as any database (MS SQL or Oracle). It has been tested with JRE 1.4 and used by me on all G6 portal versions (until 6.1 MP1 included)

    DISCLAIMER: ALTHOUGH I PERSONNALY USE THIS TOOL, THERE IS NO GUARANTY; SO USE THIS TOOL AT YOUR OWN RISK blah blah blah AND USE IT ONLY IF YOU ARE PROFFICIENT ENOUGH WITH ALUI PORTAL TECHNOLOGIES.

    2 smart moves if you are not the easily scared type of person: First, make a DB backup of the test environment you are going to refresh, and second, test it in your local environment first, and see with your own eyes that it works perfectly well :)

    For the moment, this migration utility only updates the main portal objects that contain urls:
        -Remote servers
        -Web Services
        -Portal Settings

    When I have time, I'll improve the utility and include publisher content items (especially urls embedded in them) in the list of migration objects.

    Shell scripts (.bat and .sh) are created in order to facilitate and secure the usage of this utility. The user must provide several key information for the program to run:
        -Application name (by default: portal)
        -Administration username (must be an ALUI local database user)
        -Username password
        -Pattern to look for (any valid regular expression)
        -Replacement String
        -Optional: Debug mode? (if true, details of the parsed objects is output to screen)

    The executable JAR along the appropriate launch scripts (bat for windows, sh for unix/linux) must be copied into the <PT_HOME>/bin folder in order to access the required libraries (otherwise the shell script -especially the java classpath- can be changed appropriately)

    I zipped this tool (scripts and jar) for your convenience and uploaded it (pturlreplace-1.0.zip) to my google code project (http://code.google.com/p/alui-toolbox/).

    Let me know what you think of it after you tested it. If you think it is useful, I'll update this post with new version of the tool as I come up with it. Enjoy!

    Saturday, January 12, 2008

    ALUI Portlet Monitoring Tool

    Most ALUI Portal environments will usually contain a large number of portlets, either "out-of-the-box" or custom portlets. These portlets, which range from simple bookmark links to sophisticated applications that interact with third party products such as Siebel or SAP, are indeed the major components that serve the high value functionality of your ALUI portal. Thus, it is vital that these portlets are monitored properly, so that a problem can be detected as soon as possible (preferably before your customer calls you to report the error that you had no idea was occurring...) and of course corrected asap.

    Developed by Project Performance Corporation (www.ppc.com), Portlet Monitor® is a utility designed to track the operational status of all portlets registered in any communities or mypages of your ALUI Portal environment. Although Rakesh Gupta from PPC is the creator of this product, I personally redesigned and upgraded it for version 6.X of ALUI, and thus know the internals of it inside out.

    You can contact me (fsanglier-at-ppc-dot-com) if you need additional information and pricing.

    What is it?

    Portlet monitor is a stand alone application (developed in .NET) that uses the Port

    al Server API to read the portal data, especially the community and portlet objects. It can be installed on any server that have the following components: Portal, Automation, or API Service (to be able to use the server API). Using windows automated tasks (or even ALUI automation server) portlet monitor can be configured to run at any pre-specified time.

    How does it work?

    In plain English, Portlet Monitor connect as a portal user (by initiating a portal session) and iterate through all communities, mypages and finally portlets (the ones that are actually used on the community or "My" pages) that this user has access to. For each of the portlet found, Portlet monitor will "fake" a gateway call to the remote server hosting the portlet, passing all the required portal preferences and other ALUI-specific settings to the remote portlet application.

    Error Found?

    Various types of error can be caught by portlet monitor:

    • Various HTTP Errors (500 / 401 / etc...) returned by the remote portlet application/web server.
    • Portlet Timeout errors
    • Network errors (remote portlet server has some network problems)
    • Portal exceptions (portal settings or portlet preferences missing, problem with gateway component or any other portal internal component, etc...)
    • Specific error text pattern found in the portlet (if the above errors are not found, an error can be triggered if a specific text patterns is found in a specific portlet)

    Results?

    The result of each run is locally saved in an XML file that contains the following:

    • The portlet ID
    • The community / mypage of the analyzed portlet
    • Processing Time
    • If "Broken", the last date/time the portlet was found "Working"
    • If "Broken", the cause of the error (exception trace or error code)

    After each run, an email containing the above XML report is automatically sent to the specified email list. (usually portal administrator and specific portlet developer(s))

    It is also possible to eventually serve the XML report directly in the portal through a portlet (with a XSLT applied of course)

    Performance?

    Portlet monitor can be installed on any windows server that contains either the portal, automation or API service component (It is important to note that the portal component service does not need to be running) Thus, to minimize the performance impact of portlet monitor successive runs, it is recommended to install it on a server that is not part of the live portal cluster.

    Why using this Tool versus Enterprise Monitoring Tools?

    While most enterprise monitoring tools (i.e. NETIQ) work from the component service (or process) point of view, Portlet Monitor works from the portal point of view. What does it mean exactly?

    Basically, enterprise monitoring tools are able to to monitor windows services, and eventually restart them if something wrong is happening. They are also able to monitor component log files and search for any text pattern that are relevant to an error, and if found, perform a specific action. (like restart the service) They are also able to perform a lot of other various operations...

    But what they are not able to do in a portal context like ALUI (versus Portlet Monitor) are:

    • Detect the errors before the end-user finds it (by running the portlet monitor scans at scheduled intervals) - compared to finding the errors in the log files when the end-user actually triggered the error himself...
    • Detect point of failure(s) between the portal and the portlet remote server
    • Detect portal application or database defects (i.e. gateway problem) that could induce the portlet in error (from portal point of view), even if the remote application is just working fine.
    • Detect misconfiguration of the portlet that could induce the portlet in error (from portal point of view), even if the remote application is just working fine.
    • Detect any infrastructure or software errors that would induce a timeout of the portlet.
    • Detect any portlet errors even if the monitoring agent is not running (sometimes the monitoring agent can have defect too...)
    • Detect any portlet errors even if the portlet application service is in a "Frozen" state (meaning the service is still up, the log are not showing any error, and thus the monitoring system is not reporting anything wrong, but the application is actually not responsive anymore)

    It is important to note that portlet monitor is just a monitoring and notifying tool: It does not perform any action (like restarting services etc...) other than notifying the right people.

    Last Words

    If you don't have a monitoring infrastructure in place, this tool will offer you monitor effectively the most important and valuable components of your portal (portlets).

    If you have already a monitoring infrastructure in place, this tool is not meant to replace it, but rather to be a valuable addition that completes your monitoring infrastructure already in place.