Wednesday, July 22, 2009

The Portal Scripting Interface

One of the great advantages of the WebSphere software platform is that it's been built with a great deal of flexibility. A product simply wouldn't bear the WebSphere name if there weren't several different ways to do things. WebSphere Portal Server is no exception. With the release of version 5.1 IBM has added another way to administer the configuration of the Portal. This is sure to delight the poor, overworked Portal administrator who doesn't want to learn the art of XMLAccess and wants to avoid the use of a Web-based administration interface all costs.

This new feature, named the Portal Scripting Interface, lets the portal administrator configure the system via the command line. It's an extension of the wsadmin command-line interface for WebSphere Application Server and so it uses a similar syntax including the ability to take JACL script files as input (hooray!). Believe me, this is an advance that many Portal professionals have been waiting for ever since the introduction of the wsadmin tool for AppServer.

The end result is an interface that automates portal admin tasks and eases the burden of making minute changes to nested Portal objects or transferring new portal configurations from a developer workstation.

The Portal Scripting Interface, which I'll call PSI from now on (not to be confused with pounds per square inch or some reference to psionic powers), is invoked from within the WPS_HOME\bin directory. The syntax would normally look like this:

WPS_HOME\bin\wpscript.bat

But of course it really isn't that simple. There are some implied parameters in that command. The first one is the connection type, or conntype. By default this value is SOAP, which indicates that the interface should connect to the Portal via the SOAP protocol. Another possible value could be RMI indicating that the interface should connect over IIOP. A third possible value could be NONE indicating that only the command shell should be launched and not explicitly connected to any running instance of the Portal (and not very useful for administering the portal).

The second implied parameter is the port on which to connect to the Portal. If you're using the default SOAP connection type, then the default value for the port parameter is 8882. In a Network Deployment configuration, you'd want to use the default port 8879 to make this connection. The SOAP connection port value of the server you're attempting to connect to can be viewed in the WebSphere Administration Console under Application Servers>WebSphere_Portal>End Points>SOAP Connector Address.

So an explicit string for launching the tool would look like this:

WPS_HOME\bin\wpscript.bat - conntype SOAP -port 8882

As you might expect, when WebSphere Security is enabled for the Portal, proper security credentials have to be supplied:

WPS_HOME\bin\wpscript.bat -conntype SOAP -port 8882 -
user wpsadmin -password password

Once the PSI has been launched, you must actually log into the Portal you're attempting to administer. This command, executed in the PSI, uses the syntax of the underlying wsadmin interface for AppServer. Familiarity with JACL or wsadmin would help at this point but it isn't necessary. Suffice it to say that commands are entered in a hierarchical format. They simply represent underlying Beans that are being invoked to do particular tasks. For our Portal login command, we have to invoke the Portal bean. After invoking PSI log into the Portal with:

$Portal login wpsadmin password

Congratulations! You're now connected to the Portal and ready to issue administration commands.

If you're using the new virtual portal feature of WPS 5.1, you can log into your virtual portal using a sub-command of the Portal bean. Let's say your virtual portal URI is /wps/myportal/blueportal (where the "blueportal" part of the URI indicates the name of the virtual portal), then the following commands

$Portal setvp blueportal
$Portal login wpsadmin password

will get you logged into the desired virtual portal.

Get Help Fast
Each of the beans available in this tool have help options. If I wanted to get a list of all of the available help options for the Portal bean, I could simply type

$Portal help

This would return the top-level list of help for the Portal bean. If I was more curious about just the login method of the Portal bean (which we used to log into the portal), I could type

$Portal help login

This would return help information specific to that method. The available beans in the PSI are:

$Portal
$Content
$Layout
$Portlet
$Look
$Access
$PacList

Experiment with the help function on each of them to gain a better idea of the hierarchical structure of this interface.

Work Those Index Paths!
Let's say I have a portal page hierarchy that looks like this:


Content Root
My Portal (label, uniquename:wps.myportal)
Home (page, uniquename:wps.myportal.home)
Corporate Directory (page,uniquename: wps.myportal.CorpDir)
WorkPlace (label, uniquename: wps.myportal.WorkPlace)
Email (page, uniquename: wps.myportal.WorkPlace.Email)
Docs (page, uniquename:wps.myportal.WorkPlace.Docs)

Let's think about this content-node hierarchy. If you were to think about the page structure in our example, you could assign some hierarchical values to the objects. For instance, the Content-Root we could say is at the root location of the tree, or simply /. If this were the case, then we could say that the My Portal content-node is one level down in the tree. Sort of like a directory off the root filesystem in Unix, this would be /0/1. The Home content-node, as a child of /1 would be at /0/1/2. This is called an index path.

Some examples of these index paths are as follows:


/ The root content node.
/0 The first child of the root content node.
/1 The second child of the root content node.
/0/0 The first child of the first child of the root content node.
/0/1 The second child of the first child of the root content node.
/0/2 The third child of the first child of the root content node.
0 The first child of the current content node.
1 The second child of the current content node.

The Content Bean
Content-nodes in the PSI are referenced by the Content bean. This bean lets you search for a particular content-node, view its settings, update the settings, create a new content-node or delete a content-node.

If I was curious to know some details about the Corporate Directory content-node, I could invoke the Content bean to tell me about it. The Content bean uses the following syntax for a search:

$Content find

So to find and display some info about the Corporate Directory node with uniquename wps.myportal.CorpDir, I would use:

$Content find any uniquename "wps.myportal.CorpDir"

More specifically, since I know the CorpDir is of type 'page,' I could execute a more concise search:

$Content find page uniquename "wps.myportal.CorpDir"

There are several different kinds of searches you can do. Executing

$Content help search-types

will show you these different searches. Keep in mind the help function for the Content bean is always available using:

$Content help

Okay, so big deal, you found the content-node. It's far more interesting if you were to display some other info about this node. Before you can display other attributes of the node, you have to "select" the node. Finding it isn't enough, you have to "select" it before running an additional command against it:

$Content find any uniquename "wps.myportal.CorpDir" select

Now that you've got it selected, try any of the following:

$Content get type
$Content get "wps.myportal.CorpDir" id
$Content current

The ID of the content-node (or any portal object for that matter) is the UID or Unique ID of the object. With this interface, most of the actions (get or set) are invoked against the UID of an object. Once you have this id, some of the operations become easier.

There are a few special id values that we can use. The most useful is called 'the root.'

$Content select the root

This command will select the root content node. Second in usefulness is the 'the parent' special id:

$Content select the parent

This command will select the immediate parent of the currently selected content node.

Let's say for example that the unique ID of our CorpDir node (the UID that was auto-generated by the Portal when we created the page) was found using one of the commands above. Let's say for argument's sake that this id is _6_00KJL57F9D04J770_D. We could then issue some other commands such as:

$Content get "wps.myportal.CorpDir" id
$Content get _6_00KJL57F9D04J770_Dthemename
$Content set _6_00KJL57F9D04J770_Dtheme "Finance"
$Content get _6_00KJL57F9D04J770_Dposition

If we were interested in what was underneath our WorkPlace content-node, we could select it and then search on that content-node for objects called compositions (or pages to you and me):


$Content find label uniquename
wps.myportal.WorkPlace select
$Content search composition

This will return a list of all the pages (or compositions) contained under the WorkPlace label.

But surely this isn't the exciting part. No, we're much more interested in creating some content-nodes instead of merely displaying information about them. Luckily for us, the Content bean has a method called 'create.' Let's use our CorpDir content-node as an example (we retrieved its uid in one of the above examples):

$Content select _6_
00KJL57F9D04J770_D
$Content create composition
"SubPage" html

This will select the CorpDir content-node and then create a page underneath it called SubPage with html as the supported markup.

$Content select the root
$Content create label "NewLabel"
html select
$Content create composition
"NewSubPage" html

This sequence first selects the content root, then creates a new label underneath it and selects this new label, then creates a page underneath it. By contrast, we could also delete the content-nodes:

$Content delete

This command would delete the content-node with the id specified. For safety, the system doesn't let you delete a content-node with children. Gotta make sure those kids have parents!

Lens on Portlets
Even though we can't affect portlets directly using the PSI, we can definitely get some good information about the portlets defined in our portal repository. To do so we use the Portlet bean.

$Portlet search webmodule namehas "News"

Seems pretty straightforward. This command will execute the Portlet bean with the search method against objects of the webmodule type whose names contain the word "News." Once we have those objects returned, we could take the uid of one of them and gather more info:

$Portlet get webmodule
contextroot
$Portlet get webmodule name

Of course, the Portlet bean also has a help function (as do its methods) in case you get stuck.

Sadly, there's no "set" capability with the Portlet bean. Perhaps we should start a campaign to get that functionality added...

Layout and Hierarchy
A bean that's useful for manipulating the layout of the content-nodes is the Layout bean (rather well named, I think). With the Layout bean, we can use the index path to manipulate our content-nodes. The Layout bean has several methods (that can be seen by executing $Layout help). One such method is 'move.'

$Layout move to 0

This command would move the currently selected content-node to the root position.

$Layout move by 1

This command would move the currently selected content-node 1 level down the tree. By extension, moving by -1 would move the node up the tree one notch. This could be useful if you didn't have a lot of nested pages and whatnot under the currently selected content-node. In the event that you had an incredibly complex content-node tree, you could use another of the Layout bean's methods to transfer the currently selected content-node and all of its children to another parent:

$Layout transfer to


In our page structure example, let's pretend that we got our uid values for the WorkPlace content-node (_6_00KJL57F9D04K630_A) and the Home content-node (_6_00KJL57F9D04K219_C)

$Layout transfer _6_
00KJL57F9D04K630_A to _6_
00KJL57F9D04K219_C

Once we completed this command, our new page structure would look like this:


Content Root
My Portal
Home
WorkPlace
Email
Docs
Corporate Directory

We also could have executed the "adopt" method as follows:

$Layout select _6_
00KJL57F9D04K219_C
$Layout adopt _6_
00KJL57F9D04K630_A

By first "selecting" the node we wish to have perform the adoption, we can then instruct it to do so. Very cool.

And now for something about the composition of these content-nodes that we're adopting and transferring all over the place. These content-nodes are comprised of rows and columns that together are called containers. Inside these containers we find our portlets that are known as controls.

The Layout bean can be used on both the containers and controls of a content-node.

Issuing the command below will give you the index paths of the potentially very complex layout of containers and controls on a page:

$Layout index

Appending a uid will give you the absolute index path of that object:

$Layout index

If I start off with a blank page that I've created using the Content bean, I would definitely want to use the Layout bean to create horizontal or vertical containers (rows or columns) and controls (portlets) in those containers. If we were to use the CorpDir page as an example:

$Content select _6_
00KJL57F9D04J770_D
$Layout create container
horizontal select
$Layout create control

This sequence selects the content-node we want to add the portlet to. It then creates a new row on the page and selects it. The last step is to add the portlet to that row.

If we decided later to add some other portlet to this page, we wouldn't want to have to delete the whole thing and re-create it. So in that case we could simply add to our page:

$Content select _6_00KJL57F9D04J770_D
$Layout index /0 select
$Layout create control


This sequence selects the CorpDir page by its ID. Next we select the /0 index path of the selected object. This will return us the parent container of the page (row or column we don't much care, as long as it is the top level object on the page). Lastly we add a new portlet by using its ID.

And Onward...
There are other beans that can be used to impact our portal configuration. We can use the Access bean to read in permissions or the PacList bean to assign them to various objects. And while I reviewed the major beans that one would use to administer the configuration of the portal, my comments are by no means exhaustive.

As with all things WebSphere-related, the proof is really in the hands-on tinkering. Go install WPS5.1 and play around with the Portal Scripting Interface. Before long you'll be doing more advanced tasks such as creating entire JACL scripts composed of many actions and reading them all in at once.

This interface is new. It currently has some limitations. But the direction is pretty clear. In future releases expect the PSI to increase in importance as new functions and beans are added and expanded. In fact, I would expect PSI to supplant XMLAccess as the primary automated administration interface.

There's some information in the WPS 5.1 InfoCenter regarding this new tool. It's currently located at: http://publib.boulder.ibm.com/infocenter/ wp51help/index.jsp?topic=/com.ibm.wp.ent.doc/wps/ad_psi.html.