Modify title, metadata properties of page using WebDav client

WPS 7.0 provides one more option for managing your portal pages, which is WebDav. Every portal page is not represented as folder in your WebDav.



On my local the Home -< Fun folder has 5 pages so when i go to corresponding folder in WebDav i see 5 folders. Name of the folder is either ObjectId or unique name. If i go inside a folder that represents a portal page this is what i see




  • localized_en.properties: This is properties file that has value of title and description for the page

  • metadata.properties This file represents the meta data for the page

  • staticcontent: This folder has information about the static content, such as layout.html and option to change the value



This is how the localized_en.properties file for my page looks like, if i change this file and save it using WebDav those changes get stored in the portal database. Ex. I can rename the portal page by changing value of title property in this file


description= Test PageBuilder 2 theme description
title=Test PageBuilder2 Theme


If you want to change any page level meta data values such as caching related data or template file name then you can open metadata.properties file change the corresponding value and save it back. This is how the metadata.properties file for my sample page looks like

com.ibm.portal.bookmarkable=Yes
com.ibm.portal.feed.remote-cache-expiry=86400
com.ibm.portal.layout.template.expiration=1285007105961
com.ibm.portal.IgnoreAccessControlInCaches=false
com.ibm.portal.layout.template.file.name.html=layout.html
com.ibm.portal.remote-cache-expiry=86400
com.ibm.portal.layout.template.ref=dav\:fs-type1/layout-templates/2ColumnEqual/
com.ibm.portal.layout.template.markup=html
com.ibm.portal.layout.template.lastmodified=1285007107434
com.ibm.portal.static.page.file.name.html=layout.html
com.ibm.portal.remote-cache-scope=NON-SHARED

Using WebDAV to manage portal pages

The WebSphere Portal 7.0 allows you to manage portal pages using the WebDav tool. It allows you to do following things


  • Browse through the page hierarchy. Each portal page is represented as a folder. The name of the folder is the unique name or the object ID of the page. Children pages in the topology are represented as subfolders.

  • Change globalization information of pages. To do this, users edit and save properties files that contain the globalization information.

  • Change metadata of pages. To do this, users edit and save properties files that contain the metadata information.

  • For static pages, you can browse, read, create, update, save, copy, move, and delete static content. Users can access the content of static pages via the subfolder staticcontent .

  • Delete pages.



I wanted to try this feature so first i created a WebDav connection to the http://localhost:10039/wps/mycontenthandler/dav/contentmodel/wps.content.root url like this



Once the connection is established i can see all the pages in my portal in the directory format. This is screen shot of my portal page which displays all the pages at the Content Root level



This is how they are represented in the WebDav repository. There is a folder corresponding to every portal page and lable. If you drill down in the folder you will notice there is folder corresponding to every child page,..

Working with PageBuilder2 theme .html, theme.html, skin.html

For last few days i was struggling to figure out how to modify theme.html and finally i got help from my colleagues Evan and Sanjay and now i am able to modify markup generated for theme.html. Take a look at the screen shot, i did add <h1>This is test modification in theme.html</h1> as first element to the body tag



You will have to use following steps to get it working


  • First of all create WebDav connection to /wps/mycontenthandler/dav/fs-type1 URL, this is the URL that you should use. It seems that http://localhost:10039/wps/mycontenthandler/dav/themelist url is not a valid URL for WebDav, it will keep throwing some weired error


  • Once your WebDav connection is established go to themes/PageBuilder2 folder, you will find a theme.html file here and there is locale specific version of theme.html in nls folder. I tried changing the theme.html in PageBuilder2 folder but somehow it never gets picked up instead portal always picks up locale specific version from nls folder



  • Make changes in theme.html and save those changes, if your using WebDav client(WebFolders, BitKinex) on Windows, first you will have to copy the file to local machine, modify it and then copy it back






Once your changes are updated you can refresh the page and you should be able to see the modified markup

PageBuilder 2 skin architecuter - skin.html

The PageBuilder 2 theme makes use of theme.html for defining layout of the page, it makes use of skin.html for generating markup for the skin. Note that it does not have UnlayeredContainer-H.jsp, UnlayeredContainer-V.jsp, control.jsp any more. It seems that layout.html will replace the horizontal and vertical container related functionality and the skin.html has functionality corresponding to Control.jsp.

This is how the skin.html from my local machine looks like

<div class="ibmPortalControl lotusWidget2 decoration-aria-region"><!--START LOCALE LINKS-->
<a rel="alternate" href="nls/skin_en.html" hreflang="en" class="ibmHideTemplate"></a>
<!-- decoration marks the Dojo resource name of the decoration object instantiated at the root of this layout control -->
<span style="display:none" class="decoration">com.ibm.skins.Standard.skin</span>
<!-- asa.portlet.id marks the node whose contents are the id of this layout control;
set at runtime by script in the decoration instance -->
<span style="display:none" class="asa.portlet.id"></span>
<!-- decoration classes are used by DecorationManager for adding javascript event handlers -->
<h2 class="decoration-titlebar decoration-dndHandle">
<span class="lotusLeft"> <!-- lm-dynamic-title node marks location for dynamic title support -->
<span class="lm-dynamic-title asa.portlet.title decoration-title">
<a rel="dynamic-content" href="lm:title"></a>
</span>
</span>
<a aria-haspopup="true" title="${nls.Theme:a11y_display_menu:xml}" href="javascript:;"
class="lotusIcon lotusActionMenu decoration-contextMenuAction">
<span class="lotusAltText">${nls.Theme:theme_actions:xml}</span>
</a>
</h2>
<!-- decoration-contextMenu is the anchor node to build the context menu link and widget around -->
<div style="display:none" class="decoration-contextMenu"></div>
<div class="lotusWidgetBody"> <!-- lm:control dynamic spot injects markup of layout control -->
<a rel="dynamic-content" href="lm:control"></a>
</div>
</div>


The skin.html also makes use of concept of dynamic content spot.


  • lm:title : represents the title of the portlet

  • lm:control : represents the body of the portlet

PageBuilder2 theme architecture - Dynamic Content Spot

In the PageBuilder2 theme architecture - theme.html i mentioned that the theme.html makes use of concept of dynamic content spot. The basic concept is that the theme.html want to include .jsp page, since the .html page cannot directly add .jsp page since .jsp pages need servlet context to compile and execute, those .jsps are packaged in the PageBuilder2.war along with Default.jsp.



Ex. the theme.html wants to forward control to asa.jsp for generating active sight analytics(asa) related markup, so you can include that .jsp in the theme.html like this

<a rel="dynamic-content"
href="res:/PageBuilder2/themes/html/PageBuilder2.0/asa.jsp"></a>


But this approach has following problems

  • Reference by name abstracts the dynamic content away from the implementation. This is necessary if the theme needs to run on multiple runtimes, for example WebSphere Portal and IBM® Mashup Center. The portal implementation of the navigation tabs can be a JSP that contains portal specific code. The Mashup Center on the other hand cannot execute portal JSP code, but provides an iWidget instead.

  • Reference by name isolates the theme author from having to know the underlying code information. This is useful if the theme author is an HTML and CSS designer, but not a J2EE or JavaScript developer. The HTML and CSS developer needs to know only the list of named content spots and the simple syntax to add it. This developer can then write code without having to know JSP path names etc.



So in order to provide one more layer of indirection, WPS has WP_DynamicContentSpotMappings resource provider that lets you map a symbolic name to the location of .jsp like this




Now inside your theme.html you can refer to the asa.jsp like this

<a rel="dynamic-content" href="dyn-cs:id:asa@tl:oid:csa2.theme" />


The resolver framework takes care of finding the actual .jsp file from this symbolic name. Also if you start digging into the .jsp files you will notice that they also include other .jsps by using this type of syntax


<r:dataSource uri="dyn-cs:id:configGlobal@tl:oid:csa2.theme" escape="none">
<r:param name="pragma" value="cache"/>
</r:dataSource>
<r:dataSource uri="dyn-cs:id:configDynamic@tl:oid:csa2.theme" escape="none"/>

PageBuilder2 theme architecture - theme.html

In the PageBuilder2 Theme architecture - bootstrap jsps, i mentioned that the Default.jsp of the PageBuilder2 theme does not have any HTML markup, instead it just initializing few values and then forwarding control to theme.html.

This is how the theme.html which ships with the WPS looks like. As you can see the theme.html is pretty clean and small,


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="${locale}" xml:lang="${locale}">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- rel=dynamic-content indicates an element that is replaced with the contents produced by the specified href.
dyn-cs:* URIs are resolved using the WP DynamicContentSpotMappings resource environment provider. These values can
also be set using theme metadata if a theme is specified in the URI (e.g. @tl:oid:theme_unique_name). -->
<link rel="dynamic-content" href="dyn-cs:id:head@tl:oid:csa2.theme">
<script type="text/javascript">
dojo.addOnLoad(function(){
com.ibm.pb.themes.commonInit({
setWindowTitle:true,
useNavigationController: true,
useRenderingController: true,
useDNDController: true,
initLiveTextService: true,
lazyLoadModeWidgets: true,
navPrimingContainers: ["selectionPathPrimer","topNavLinks","navTabsRoot"],
customInit: com.ibm.themes.PageBuilder2.init
});
dojo.publish("com.ibm.portal.theme.portlet_ready"); // notifies ASA that portlet IDs are ready to be found in the DOM
});
</script>
<!-- rendering is delegated to the specified href for each locale --><!--START LOCALE LINKS-->
<link rel="alternate" href="nls/theme_en.html" hreflang="en">
</head>
<body class="lotusui tundra${rtl| lotus_rtl mumrtl} locale_${locale}" ${bidi.dir.attribute} >

<div class="lotusFrame">
<div class="lotusui lotusTitleBar">
<div class="lotusRightCorner">
<div class="lotusInner">
<a rel="dynamic-content" href="dyn-cs:id:tabNav@tl:oid:csa2.theme"></a>
<div style="clear: both;"></div>
</div>
</div>
</div><!--end titleBar-->
<a rel="dynamic-content" href="dyn-cs:id:pageToolbar@tl:oid:csa2.theme"></a>
<div class="lotusMain" id="lotusMain">
<!-- pb-pageMode-edit indicates that an iwidget should be lazy-loaded upon entering edit mode for the page -->
<div class="iw-iWidget iw-Standalone pb-pageMode-edit" id="customizeShelfContainer">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/customizeShelf.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div style="clear:both;"></div>
<a id="lotusMainContent" name="lotusMainContent"></a>
<div id="layoutContainers" class="ibmLayoutContainers ibmLayoutContainersHidden" role="main">
<a rel="dynamic-content" href="dyn-cs:id:layout@tl:oid:csa2.theme"></a>
</div>
</div><!--end main-->
<div class="lotusFooter"></div><!-- page footer -->
</div><!--end frame-->
<!-- active site analytics additions -->
<a rel="dynamic-content" href="dyn-cs:id:asa@tl:oid:csa2.theme"></a>
<!-- This is responsible for bootstrapping the configuration for the javascript framework.
This is located here instead of the head section to improve client performance. -->
<a rel="dynamic-content" href="dyn-cs:id:config@tl:oid:csa2.theme"></a>

<div id="systemWidgets">
<div class="iw-iWidget iw-Standalone" id="templateLayout">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/templateLayout.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone" id="pageActionsMenu">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/ContentSetMenu.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
<span class="iw-ItemSet" title="attributes" style="display: none;">
<a class="iw-Item" href="#contextMenuID">pageActions</a>
<a class="iw-Item" href="#anchorCSSClass">lotusCommonActionMenuAnchor</a>
<a class="iw-Item" href="#menuCSSClass">lotusCommonActionMenu</a>
<a class="iw-Item" href="#resourceType">com.ibm.mashups.enabler.navigation.NavigationNode</a>
<a class="iw-Item" href="#openEvent">PageActions.open</a>
<a class="iw-Item" href="#closeEvent">PageActions.close</a>
</span>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone" id="userActionsMenu">
<a class="iw-Definition" href="/mccbuilder/widget-catalog/ContentSetMenu.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
<span class="iw-ItemSet" title="attributes" style="display: none;">
<a class="iw-Item" href="#contextMenuID">userActions</a>
<a class="iw-Item" href="#anchorCSSClass">lotusCommonActionMenuAnchor</a>
<a class="iw-Item" href="#menuCSSClass">lotusCommonActionMenu</a>
<a class="iw-Item" href="#resourceType">com.ibm.mashups.enabler.user.User</a>
<a class="iw-Item" href="#openEvent">UserActions.open</a>
<a class="iw-Item" href="#closeEvent">UserActions.close</a>
</span>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone pb-pageMode-edit" id="newPage">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/NewPageDialog.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
<span class="iw-ItemSet" style="display:none" title="attributes">
<a class="iw-Item" href="#controller">ibmCfg.controllers.navigation</a>
<a class="iw-Item" href="#allowFriendlyURL">true</a>
<a class="iw-Item" href="#allowPrivate">true</a>
</span>
</div>
<!-- The lazyLoad attribute is used for widgets that are explicitly loaded by another source at a later point in time
(in this case the displayHelper). -->
<div class="iw-iWidget mumHiddenWidget iw-Standalone" lazyLoad="true" id="sharePage">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/accessControl.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone" lazyLoad="true" id="reorderPage">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/reorderPageWidget.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone" lazyLoad="true" id="viewMorePage">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/viewMorePage.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone" lazyLoad="true" id="wireInterface">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/wireInterfaceWithSettings.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
<span class="iw-ItemSet" title="attributes" style="visibility: hidden; display: none">
<a class="iw-Item" style="visibility:hidden;display:none;" href="#displaySettings">true</a>
<a class="iw-Item" style="visibility:hidden;display:none;" href="#displayPortletsAndWidgetsWarningMessage">true</a>
</span>
</div>
<div class="iw-iWidget mumHiddenWidget iw-Standalone pb-pageMode-edit" id="autoWiringManager">
<a class="iw-Definition"
href="/mccbuilder/widget-catalog/autoWiringManager.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"></a>
</div>
<div class="iw-iWidget iw-Standalone" id="dialogDisplayer">
<a class="iw-Definition" style="visibility:hidden;display:none;"
href="/mccbuilder/widget-catalog/displayHelper.xml?pragma=cache&max-age=1209600&cache-scope=public&vary=none"> </a>
<span class="iw-ItemSet" title="attributes" style="visibility: hidden; display: none;">
<a class="iw-Item" style="visibility:hidden;display:none;" href="#sharePage">sharePage</a>
<a class="iw-Item" style="visibility:hidden;display:none;" href="#reorderPage">reorderPage</a>
<a class="iw-Item" style="visibility:hidden;display:none;" href="#viewMorePage">viewMorePage</a>
<a class="iw-Item" style="visibility:hidden;display:none;" href="#wireInterface">wireInterface</a>
<a class="iw-Item" style="visibility:hidden;display:none;" href="#autoWiringManager">autoWiringManager</a>
</span>
</div>
</div>
</body>
</html>



If you compare the theme.html to the markup generated for the portal page you will notice that the portal page has more markup(as expected it has markup generated by portal, markup for navigation,..)



Also if you compare this markup to the markup generated for portal page you will notice that most of the markup for normal page is generated inside div class="lotusFrame", which is the highlighted code. There is lot of code under div id="systemWidgets" but my guess is that code kicks in only in case of iwidget on a page.

Now the basic question would be then who is generating the portal markup, who takes care of generating navigation, forwarding control to portal aggregation engine,.. The answer would be its the dynamic content spots in the .html

PageBuilder2 Theme architecture - bootstrap jsps

In the PageBuilder2 theme architecture i mentioned that first thing that Default.jsp does is forward control to bootstrap.jspf and bootstrapPortal.jspf.

These two files are used for calculating portal level variables such as


  • isPageRenderModeCSA: If the page render mode is CSA or SSA

  • Locale: Avaiable locale, default locale

  • user Id: user id of the anonymous and authenticated user, if user is logged in

  • ContentHandlerURI: The URI for the ContentHandler by default it will always be /wps/contenthandler for anonymous or /wps/mycontenthandler for authenticated user, this URI is also used a base for all the resources

  • portalContext: /wps

  • portalProxyUrl: /wps/proxy

  • Dojo information: dojoRoot /portal_dojo/v1.4.3 and dojoContextRoot is /portal_dojo

  • themeWebDAVBaseURI: dav:fs-type1/themes/PageBuilder2/

  • themeWebAppBaseURI: /PageBuilder2/themes/html/PageBuilder2

  • colorPalette: By default its empty but you can override these values at page level

  • pageStyle:By default its empty but you can override these values at page level

  • navTabsLevel,navTabRootNode: Navigation generation related information

PageBuilder2 theme architecture - Default.jsp

IBM introduced PageBuilder2 theme in WPS 7.0, it allows user to define the theme using static html file, it seems that there are different pieces and i wanted to check how the different pieces fit together, so i started debugging theme and these are my notes

Even though the PageBuilder2 theme is changed one thing is still same which is Default.jsp file in the theme acts as entry point, it controls the overall theme. This is how the Default.jsp of PageBuilder2 theme looks like


<%@ page session="false" buffer="none" %>
<%@ page trimDirectiveWhitespaces="true" %>
<%-- Licensed Materials - Property of IBM, 5724-E76, (C) Copyright IBM Corp. 2001, 2004, 2006, 2010 - All Rights reserved. --%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v7.0/portal-core" prefix="portal-core" %>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v7.0/portal-logic" prefix="portal-logic" %>
<%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v7.0/portal-fmt" prefix="portal-fmt" %>
<%@taglib uri="/WEB-INF/tld/portal-internal.tld" prefix="portal-internal" %>
<%@taglib uri="/WEB-INF/tld/resolver-v7.tld" prefix="r" %>
<portal-core:constants/>
<portal-core:defineObjects/>
<portal-internal:adminNavHelper/>
<%@ include file="./bootstrap.jspf" %>
<%@ include file="./bootstrapPortal.jspf" %>
<%-- The theme template is determined by whether there is a value set in page meta data,
if no value is set in the meta data, then it defaults to the template stored in webdav --%>
<c:choose>
<c:when test="${empty themeWebDAVBaseURI}">
<c:set var="themeTemplateURI" value="" />
</c:when>
<c:when test="${empty dirMD['com.ibm.portal.theme.template.file.name.html']}">
<c:set var="themeTemplateURI" value="${themeWebDAVBaseURI}theme.html" />
</c:when>
<c:otherwise>
<c:set var="themeTemplateURI" value="${themeWebDAVBaseURI}${dirMD['com.ibm.portal.theme.template.file.name.html']}" />
</c:otherwise>
</c:choose>
<c:choose>
<c:when test="${!empty themeTemplateURI}">
<r:dataSource uri="spa:${wp.identification[wp.selectionModel.selected]}" escape="none">
<r:param name="themeURI" value="${themeTemplateURI}"/>
<r:param name="mime-type" value="text/html"/>
</r:dataSource>
</c:when><%-- If no theme template is found, the fallback.jsp is rendered--%>
<c:otherwise>
<%@ include file="./fallback.jsp" %>
</c:otherwise>
</c:choose>


The Default.jsp is very simple and it does not have any HTML markup generation code at all. The functionality of Default.jsp can be broken into 3 parts


  • Initializing variables required for the theme: At the start of the Default.jsp it is forwarding control to bootstrap.jspf and bootstrapPortal.jspf, It looks like these two files are used for initializing all the variables that are required for theme. Things like if user is logged in, if yes what is userId, available locale, paths to contenthandler and also some variables that are required for calculating themeTemplateURI

  • Cacluate value of themeTemplateURI Next it tries to calculate value of themeTemplateURI. In the default implementation it will always be dav:fs-type1/themes/PageBuilder2/theme.html but your allowed to override this value at page level as well as at theme level

  • Forwarding control to r:dataSource for generating markup Once the value of themeTemplateURI is calculated control will fowarded to r:dataSource jsp tag, and this tag will be responsible for parsing theme.html, evaluating dynamic content spot, and generating final html markup

Where is source code for Page Builder 2 theme

The WebSphere portal server has a very different directory layout/ application deployment structure compared to the previous version, i think this was done to support multiple profiles but i need to dig into that part.

I am trying to learn about PageBuilder2(CSA2) theme that was introduced in WPS 7.0, so i thought i will look into the source code to find out how it works so i went to wp_profiles/installedApps folder but i could not see PageBuilder2.ear. In fact it seems that installedApps folder has few applications



But when i tried accessing any portal page i could see some PageBuilder2 theme related jsp's being initialized

[9/29/10 6:24:12:832 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/Default.jsp]: Initialization successful.
[9/29/10 6:24:14:684 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/head.jsp]: Initialization successful.
[9/29/10 6:24:21:426 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/bannerNav.jsp]: Initialization successful.
[9/29/10 6:24:21:581 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/search.jsp]: Initialization successful.
[9/29/10 6:24:21:598 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/bannerCommonActions.jsp]: Initialization successful.
[9/29/10 6:24:22:210 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/status.jsp]: Initialization successful.
[9/29/10 6:24:22:460 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/tabNav.jsp]: Initialization successful.
[9/29/10 6:24:22:501 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/pageToolbar.jsp]: Initialization successful.
[9/29/10 6:24:23:306 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/skins/html/UnlayeredContainer-H.jsp]: Initialization successful.
[9/29/10 6:24:23:331 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/skins/html/UnlayeredContainer-V.jsp]: Initialization successful.
[9/29/10 6:24:24:628 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/asa.jsp]: Initialization successful.
[9/29/10 6:24:24:759 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/config.jsp]: Initialization successful.
[9/29/10 6:24:24:987 PDT] 00000081 servlet I com.ibm.ws.webcontainer.servlet.ServletWrapper init SRVE0242I: [PageBuilder2_Theme] [/PageBuilder2] [/themes/html/PageBuilder2/configDynamic.jsp]: Initialization successful.


So i went to wps_profile/temp folder, which will have .class file for every .jsp file that gets complied into .java first and then .class file and i could see a PageBuilder2_Theme and many other folders related application that are not there in installedApps




Since the temp folder had a PageBuilder2_Theme folder and it had .class files corresponding to .jsp's used by theme that confirmed that there is a .ear file behind it. So i checked the wp_profile/config/cells/localhost/application folder which is used for storing configuration for every .ear file that is installed on the server and there i could see PageBuilder2_Theme.ear file like this




Once you find the directory corresponding to the application that your looking for in wp_profile/config/cells/localhost/application folder, it becomes easy, you can go to PageBuilder2_theme/deployments/PageBuilder2_Theme folder and there you can find the deployment.xml which has information about where this application is actually installed. This is how the deployment.xml for PageBuilder2_Theme looks like on my machine


<?xml version="1.0" encoding="UTF-8"?>
<appdeployment:Deployment xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI"
xmlns:appdeployment="http://www.ibm.com/websphere/appserver/schemas/5.0/appdeployment.xmi"
xmi:id="Deployment_1282248412893">
<deployedObject xmi:type="appdeployment:ApplicationDeployment" xmi:id="ApplicationDeployment_1282248412894"
deploymentId="0" startingWeight="100" binariesURL="${WPS_HOME}/theme/wp.mashup.cc.theme/installedApps/wp.mashup.cc.theme.ear"
useMetadataFromBinaries="false" enableDistribution="false" createMBeansForResources="true" reloadEnabled="false"
appContextIDForSecurity="href:localhost/PageBuilder2_Theme" zeroEarCopy="true"
filePermission=".*\.dll=755#.*\.so=755#.*\.a=755#.*\.sl=755" allowDispatchRemoteInclude="false" allowServiceRemoteInclude="false"
asyncRequestDispatchType="DISABLED">
<targetMappings xmi:id="DeploymentTargetMapping_1282248412894" enable="true" target="ServerTarget_1282248412894"/>
<classloader xmi:id="Classloader_1282248412894" mode="PARENT_LAST"/>
<modules xmi:type="appdeployment:WebModuleDeployment" xmi:id="WebModuleDeployment_1282248412894" deploymentId="1"
startingWeight="10000" uri="PageBuilder2.war">
<targetMappings xmi:id="DeploymentTargetMapping_1282248412895" target="ServerTarget_1282248412894"/>
<classloader xmi:id="Classloader_1282248412895"/>
</modules>
<properties xmi:id="Property_1282248412894" name="metadata.complete" value="true"/>
</deployedObject>
<deploymentTargets xmi:type="appdeployment:ServerTarget" xmi:id="ServerTarget_1282248412894" name="WebSphere_Portal"
nodeName="localhost"/>
</appdeployment:Deployment>


In this file if you search for binariesUrl you will find the location where this .ear file is actually installed which is ${WPS_HOME}/theme/wp.mashup.cc.theme/installedApps/wp.mashup.cc.theme.ear. So i went to that folder and i could find the source code for PageBuilder2 theme there.

Theme in WPS 7.0

One of the biggest change in the WebSphere Portal Server 7.0 is that it has a new theme called PageBuilder2(CSA2) theme, which has a different architecture that allows you to write theme in .html and use webdav,.. I wanted to learn how this theme works and how different pieces fit together, and these are my notes

Until version 6.1 source code for all the different themes that were shipped with WebSphere portal used to be located in wp_profile/installedApps/localhost/wps.ear/wps.war/themes/html/ directory, so i went to check that directory first and it seems that now that directory is almost empty, this is the default content.



Now it only as Default.jsp and CloseWindow.jsp. If you open the Default.jsp you will notice its much simpler and smaller compared to previous versions and from the comment it looks like this is the fallback minimal version of theme which will get called if your actual theme does not work and it gives you chance to recover.

So i did full export of websphere portal using xmlaccess and searched for <theme> element and i can find 4 theme elements with PageBuilder2 theme set as default theme

<theme action="update" active="true" context-root="/PortalTheme" default="false" defaultskinref="ZK_CGAH47L0085810IAHU76SD20S4"
domain="rel" objectid="ZJ_CGAH47L0085810IAHU76SD20H0" resourceroot="Portal" uniquename="ibm.portal.theme.Portal">
<localedata locale="en">
<title>Portal</title>
</localedata>
<allowed-skin skin="ZK_CGAH47L0085810IAHU76SD20S2" update="set"/>
<allowed-skin skin="ZK_CGAH47L0085810IAHU76SD20S4" update="set"/>
<allowed-skin skin="ZK_CGAH47L0085810IAHU76SD20S6" update="set"/>
<parameter name="com.ibm.portal.theme.hasBaseURL" type="string" update="set"><![CDATA[true]]></parameter>
</theme>

<theme action="update" active="true" context-root="/PageBuilder2" default="true" defaultskinref="ZK_CGAH47L00OES90IAH10FQR3KJ2"
domain="rel" objectid="ZJ_CGAH47L00OES90IAH10FQR3KJ6" resourceroot="PageBuilder2" uniquename="csa2.theme">
<localedata locale="en">
<title>Page Builder</title>
</localedata>
<allowed-skin skin="ZK_CGAH47L0085810IAHU76SD20S5" update="set"/>
<allowed-skin skin="ZK_CGAH47L00OES90IAH10FQR3KJ2" update="set"/>
<parameter name="com.ibm.portal.themetype" type="string" update="set"><![CDATA[CSA2]]></parameter>
<parameter name="theme.capability.dojo" type="string" update="set"><![CDATA[1.4.3]]></parameter>
<parameter name="theme.capability.oneUI" type="string" update="set"><![CDATA[2.1]]></parameter>
<parameter name="com.ibm.portal.layout.template.href" type="string" update="set"><![CDATA[dav:fs-type1/layout-templates/2ColumnEqual/]]></parameter>
<parameter name="theme.capability.mashups.enabler" type="string" update="set"><![CDATA[2.4]]></parameter>
<parameter name="com.ibm.portal.theme.template.ref" type="string" update="set"><![CDATA[dav:fs-type1/themes/PageBuilder2/]]></parameter>
</theme>

<theme action="update" active="true" context-root="/themes" default="false" defaultskinref="ZK_OGFLMKG108IGF0IQCG6O9610O3"
domain="rel" objectid="ZJ_OGFLMKG108IGF0IQCG6O961045" resourceroot="defaultTheme" uniquename="com.ibm.portal.mashup.theme.defaultTheme">
<localedata locale="en">
<title>Breadcrumb - Free Form Layout </title>
<description>Breadcrumb - Free Form Layout</description>
</localedata>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O1" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O2" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O3" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O4" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O5" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O6" update="set"/>
<parameter name="com.ibm.portal.themetype" type="string" update="set"><![CDATA[mashup]]></parameter>
<parameter name="preview-url" type="string" update="set"><![CDATA[preview.png]]></parameter>
<parameter name="com.ibm.portal.themestructure" type="string" update="set"><![CDATA[mashup]]></parameter>
<parameter name="com.ibm.mashups.theme.body.class" type="string" update="set"><![CDATA[mashups]]></parameter>
</theme>
<theme action="update" active="true" context-root="/themes" default="false" defaultskinref="ZK_OGFLMKG108IGF0IQCG6O961041" domain="rel"
objectid="ZJ_OGFLMKG108IGF0IQCG6O961043" resourceroot="defaultThemeColumned" uniquename="com.ibm.portal.mashup.theme.defaultThemeColumned">
<localedata locale="en">
<title>Breadcrumb - Column Layout</title>
<description>Breadcrumb - Column Layout</description>
</localedata>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O961040" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O961041" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O961042" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O961044" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O961046" update="set"/>
<allowed-skin skin="ZK_OGFLMKG108IGF0IQCG6O9610O7" update="set"/>
<parameter name="com.ibm.portal.themetype" type="string" update="set"><![CDATA[mashup]]></parameter>
<parameter name="preview-url" type="string" update="set"><![CDATA[preview.png]]></parameter>
<parameter name="com.ibm.portal.themestructure" type="string" update="set"><![CDATA[mashup]]></parameter>
<parameter name="com.ibm.mashups.theme.body.class" type="string" update="set"><![CDATA[mashups]]></parameter>
</theme>


The xmlaccess export of the portal has 4 themes

  1. Portal

  2. PageBuilder

  3. Breadcrumb - Free Form Layout

  4. Breadcrumb - Column Layout



But if you login into WPS admin console and go to Themes and Skins portlet you will notice that it displays only 2 themes one is Portal and other is Page Builder. Also when you try to change theme of your portal page you will see only these two themes there. I guess the themes with themetype equal to mashup cannot be applied to page and it does not show up in the Theme and skin portlet



It looks like the WPS 7.0 makes use of packaging theme in separate ear concept that was introduced in the WPS 6.1. The source code for theme is distributed in 3 separate .ear files. This the mapping for the theme name to the context root.


  1. Portal -> /PortalTheme

  2. Page Builder -> /PageBuilder2

  3. Breadcrumb - Free Form Layout -> /themes

  4. Breadcrumb - Column Layout -> /themes



Also it seems that the source code for the theme is distributed at different locations and all of them are installed inside PortalServer directory which is a read only directory.

  • Portal : ${WPS_HOME}/installer/wp.ear/installableApps/wps_theme.ear

  • Page Builder : ${WPS_HOME}/theme/wp.mashup.cc.theme/installedApps/wp.mashup.cc.theme.ear

  • Breadcrumb - Free Form Layout : ${WPS_HOME}/base/wp.mmi.deploy/installedApps/MashupMaker_Integration.ear/theme.war

  • Breadcrumb - Column Layout : ${WPS_HOME}/base/wp.mmi.deploy/installedApps/MashupMaker_Integration.ear/theme.war