This document describes two REST Services available in WebSphere Portal as of version 6.1. The Remote State Service enables you to decode the navigational state information from a given WebSphere Portal URL, or, vice versa, encode an existing XML state representation to a portal URL. The Fragment Service can be used to interact with a particular portlet individually, e.g. to retrieve the markup of the portlet’s doView method only without rendering the complete portal page.
Basics: Page and Portlet Window IDs. 2
Remote State Service. 3
General Description. 3
Usage Examples. 4
Portlet Fragment Service. 7
Usage Example. 8
Sample portlets. 9
Usage example: 10
Basics: Page and Portlet Window IDs
Both services described in this document use references to two kinds of portal resources: pages and portlet windows. Pages represent a complete portal page in the navigation hierarchy; portlet windows represent the layout control for a particular instance of a portlet on a page. When referring to pages or portlet windows in the services, you can address the resources either by unique name or by the string representation of the internal unique identifier, also called object id or oid. For pages, you can retrieve the unique identifier or set the unique name with the “Custom Unique Names” administration portlet:
The identifiers or unique names for portlet windows are not directly manageable through the administrative portlets, but can be retrieved or set using the XML configuration interface (see http://publib.boulder.ibm.com/infocenter/wpdoc/v6r1/topic/com.ibm.wp.ent.doc_v6101/admin/admxmlai.html
). For example, in an XML export of a single page, you might find the following structure and add the unique name element for a particular portlet window, represented by the element enclosing the respective portlet instance:
<?xml version="1.0" encoding="UTF-8" ?>
<request xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" build="wp6102_023_01" type="update" version="6.1.0.2" xsi:noNamespaceSchemaLocation="PortalConfig_6.1.0.2.xsd">
<portal action="locate">
…
<content-node action="locate" domain="rel" objectid="6_000000000000000000000000A0" uniquename="wps.content.root" />
<content-node action="locate" domain="rel" objectid="6_CGAH47L00OQBD0I0LUN96N00I3" uniquename="ibm.portal.Home" />
<content-node action="update" active="true" allportletsallowed="true" content-parentref="6_CGAH47L00OQBD0I0LUN96N00I3" create-type="explicit"
domain="rel" objectid="6_AESU3F5408QK30I4FE8ELO1000" ordinal="1600" type="page" uniquename="wp.home.sampleview">
<supported-markup markup="html" update="set" />
<localedata locale="en">
<title>Sample View</title>
</localedata>
<access-control externalized="false" owner="uid=wpsadmin,o=defaultWIMFileBasedRealm" private="false" />
<component action="update" active="true" deletable="undefined" domain="rel" modifiable="undefined" objectid="7_AESU3F5408QK30I4FE8ELO1004"
ordinal="100" orientation="H" skinref="undefined" type="container" width="undefined">
<component action="update" active="true" deletable="undefined" domain="rel" modifiable="undefined" objectid="7_AESU3F5408QK30I4FE8ELO1002"
ordinal="100" orientation="V" skinref="undefined" type="container" width="undefined">
<component action="update" active="true" deletable="undefined" domain="rel" modifiable="undefined" objectid="7_AESU3F54081700IK44VSPE1007"
ordinal="100" skinref="undefined" type="control" width="undefined"
uniquename="ibm.portal.sampleview.portletwindow">
<portletinstance action="update" domain="rel" objectid="5_AESU3F54081700IK44VSPE1003" portletref="3_AESU3F54081700IK44VSPE1002" />
</component>
</component>
<component action="update" active="true" deletable="undefined" domain="rel" modifiable="undefined" objectid="7_AESU3F5408QK30I4FE8ELO1006"
ordinal="200" orientation="V" skinref="undefined" type="container" width="undefined" />
</component>
</content-node>
</portal>
<status element="all" result="ok" />
</request>
The portlet window identifier for a particular portlet instance can also be retrieved in the portlet code itself (where it e.g. may be passed on as a parameter to other resources) by the PortletRequest.getWindowID method available with the JSR 286 standard. Within JSPs that use the portlet-client-model tag library of WebSphere Portal, the portlet window id is available by the variable portletWindowID, as shown in the following code snippet.
Alternatively, the information about page and portlet window identifiers is available remotely using the REST services for the content model or the navigation model, respectively (see http://publib.boulder.ibm.com/infocenter/wpdoc/v6r1/topic/com.ibm.wp.ent.doc_v6101/dev/rest.html
).
Remote State Service
The purpose of this REST service is to encode and decode navigational state to and from WebSphere Portal URLs. This is useful if requests with a particular navigational state need to be sent to Portal from clients that do not have access to the WebSphere Portal Java APIs. This could for example be the case from Javascript code, from a rich client platform or custom non-java code.
The remote state service introduces the state URI scheme. The scheme specific portion of the URI identifies the state that is to be encoded or decoded:
- Decoding of URLs: the scheme specific part contains an absolute or full-path portal URL. In this mode the service will decode the state represented by the URL and return the respective XML document.
- Encoding of URLs (raw): the scheme specific part contains the raw XML document in clear text. Make sure to properly URL escape the document to make it a valid scheme part (as defined in RFC1738, see http://www.ietf.org/rfc/rfc1738.txt
).
- Encoding of URLs (compressed): the scheme specific part contains a compressed version of the XML document. First the raw XML document is compressed with the gzip algorithm. The resulting byte stream is then converted to a character stream via base64 encoding using the standard base64 alphabet, but without line breaks. This character stream forms the scheme specific part of the URI. Make sure to properly URL escape the document to make it a valid scheme part (as defined in RFC1738).
The encoding process is triggered by sending a GET request to the POC servlet with the parameter mode=download. The server responds with an ATOM feed that describes the state, including the Portal URL to the state as the alternate atom:link. Due to the potentially large size of the state URIs the encoding process can also be triggered via a POST request. In this case the XML document is sent as part of the request body to the Content Handler servlet with a URI of state:encode.
Decode a Portal URL
To decode the portal URL
/wps/myportal/!ut/p/c5/04_...A9DZao/dl3/d3/L3dDb0EvUU5RTGtBISEvWUZSdndBISEvNl9BRVNVM0Y1NDA4UUszMEk0RkU4RUxPMTBHNw!!/
perform the following request to the POC servlet in WebSphere Portal:
/wps/mypoc?uri=state:/wps/myportal/!ut/p/c5/04_...A9DZao/dl3/d3/L3dDb0EvUU5RTGtBISEvWUZSdndBISEvNl9BRVNVM0Y1NDA4UUszMEk0RkU4RUxPMTBHNw!!/&mode=download
This request returns an XML representation of the navigational state that is encoded in the portal URL, like
<?xml version="1.0" encoding="UTF-8"?>
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO10G7">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
<screen-template/>
</state>
</root>
Encode a Portal URL
Clients can use the remote state service to generate WebSphere Portal URLs from an XML description of the state. There are three different ways how you can send the state information to the service:
- POST request: Send the XML string via a POST request to
/wps/[my]contenthandler?uri=state:encode
- Direct encoding: Literally take the bytes of the XML string and construct a URI out of them
state:%3C?xml%20version=%221.0%22%20encoding=%22UTF-8%22?%3E%0D%0A%3Croot%3E...rget%3E%0D%0A%3C/root%3E%0D%0A
From this URI create a URL to the POC servlet:
/wps/[my]poc?uri=state%3a%253C%3fxml%2520version%3d%25...arget%253E%250D%250A%253C%2froot%253E%250D%250A&mode=download
Send a GET request to this URL.
- Compressed encoding: Literally take the bytes of the XML stream and compress them using the gzip algorithm. Convert the resulting stream into a base64 character sequence without line breaks and construct a state URI out of this.
state:H4sIAAAAAAAAAK2Sb0/DIBDGvwrhfTuYy9Y...PuHIqC6Z7on162LQj/gWICyi5DwMAAA==
From this URI create a URL to the POC servlet:
/wps/[my]poc?uri=state%3aH4sIAAAAAAAAAK2Sb0%2fDIBDGvw...2fGn9fGO5GMPuHIqC6Z7on162LQj%2fgWICyi5DwMAAA%3d%3d&mode=download
Note that the URL paths for the POC or Content Handler servlets in WebSphere Portal distinguish depending on user authentication. For unauthenticated access, the default paths are /wps/poc or /wps/contenthandler, for authenticated access /wps/mypoc or /wps/mycontenthandler.
In all encoding cases the URL is actually accessed via a GET request and results in a cacheable ATOM response:
<atom:entry>
<atom:id>
state:/wps/myportal/!ut/p/c4/04_SB8K8xLLM9MSSzPy8xBz9CP0os3hH1-BQYzdTEwOLQG9jA08TN1cLVx9_.../
</atom:id>
<atom:updated>1970-01-01T00:00:00.000Z</atom:updated>
<atom:link href="/wps/myportal/!ut/p/c4/04_SB8K8xLLM9MSSzPy8xBz9CP0os3hH1-BQYzdTEwOLQG9jA08TN1cLVx9_.../"/>
<atom:content type="application/xml">
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO10G7">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
</state>
</root>
</atom:content>
</atom:entry>
The alternate link of this response contains the encoded URL.
Examples for state information
Although the format of the XML state representation can be considered as public, there is no complete description of the syntax and semantics. The following section shows some example XML representations of the navigational state for several common use cases like actions, defining render parameters, and resource requests. In all examples, the portlet-id points to the portlet window as described in the introduction.
Portlet action
<?xml version="1.0" encoding="UTF-8"?>
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO1000">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
<parameters>
<param name="ibm.inv"><value>119654563203</value></param>
</parameters>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
<portlet id="7_AESU3F5408QK30I4FE8ELO10O0"/>
</state>
<target portlet-id="7_AESU3F5408QK30I4FE8ELO10O0" id="sskzF44160022">
<target-type>action</target-type>
</target>
</root>
Render parameters
<?xml version="1.0" encoding="UTF-8"?>
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO1000">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
<portlet id="7_AESU3F5408QK30I4FE8ELO10O0">
<parameters>
<param name="test1"><value>value1</value></param>
</parameters>
</portlet>
</state>
<target portlet-id="7_AESU3F5408QK30I4FE8ELO10O0"/>
</root>
Public render parameters
<?xml version="1.0" encoding="UTF-8"?>
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO1000">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
<portlet id="7_AESU3F5408QK30I4FE8ELO10O0"/>
<shared-parameters id="global">
<shared-parameter nsuri="http://RemoteStateAndFragmentAPIViewPortlet/" localpart="TestPublicRenderParam">
<value>value1</value>
</shared-parameter>
</shared-parameters>
</state>
<target portlet-id="7_AESU3F5408QK30I4FE8ELO10O0"/>
</root>
Resource request
<?xml version="1.0" encoding="UTF-8"?>
<root>
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO1000">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000"/>
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3"/>
<node id="6_000000000000000000000000A0"/>
</expansions>
<theme-template>Home</theme-template>
</state>
<target portlet-id="7_AESU3F5408QK30I4FE8ELO10O0">
<target-type>resource</target-type>
<resourceCacheability>cacheLevelPage</resourceCacheability>
</target>
</root>
For other, more specialized use cases, it is recommended to decode respective existing URLs that have been generated by a server side API and analyze the decoding result.
The fragment service allows to interact with a single portlet, e.g. to retrieve the markup of the doView method of a particular portlet individually. The service introduces the fragment URI scheme that takes the object id or unique name of the portlet window and the portal page as identifiers, according to the format fragment:pm:oid:@oid:. This URI is then attached as a parameter to the normal Portal URL that would be used to access the respective portal page; this way it is also possible to set render parameters or trigger actions in the portlet by encoding those in the URL. If a correct fragment URI is attached to the URL, the portal returns an ATOM feed with one entry that contains meta information and the portlet markup as its content.
To get the fragment markup of a portlet instance with portlet window id 7_AESU3F5408QK30I4FE8ELO10O0 that is placed on a page with the unique name wp.home.sampleview, first generate a normal Portal URL that addresses this page:
/wps/myportal/!ut/p/c5/04_SB8K8xLLM9MSSzPy8xBz9CP0os3hH1…x1ZTE!/
Then build the fragment URI in the following format
fragment:pm:oid:7_AESU3F5408QK30I4FE8ELO10O0@oid:wp.home.sampleview
Add this URI and the additional mode parameter to the portal URL
/wps/myportal/!ut/p/c5/04_SB8K8xLLM9MSSzPy8xBz9CP0os3hH1…x1ZTE!/?uri=fragment:pm:oid:7_AESU3F5408QK30I4FE8ELO10O0@oid:wp.home.sampleview&mode=download
This returns the following ATOM feed containing an ATOM entry representing the portlet instance. Important elements are the links to fragments of the portlet for the different window states (maximized, minimized), portlet modes (not visible in the example as the portlet does only implement the view mode), and the portlet markup in the CDATA element within the atom:content section.
<?xml version="1.0" encoding="UTF-8" ?>
<atom:feed xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:portal="http://www.ibm.com/xmlns/prod/websphere/portal/v6.0.1/portal-model" xmlns:atom="http://www.w3.org/2005/Atom">
<atom:id>oid:6_AESU3F5408QK30I4FE8ELO1000</atom:id>
<atom:title>Sample View</atom:title>
<root xmlns="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portal-state">
<state type="navigational">
<selection selection-node="6_AESU3F5408QK30I4FE8ELO1000">
<mapping src="6_CGAH47L00OQBD0I0LUN96N00I3" dst="6_AESU3F5408QK30I4FE8ELO1000" />
<parameters />
</selection>
<expansions>
<node id="6_CGAH47L00OQBD0I0LUN96N00I3" />
<node id="6_000000000000000000000000A0" />
</expansions>
<theme-template>Home</theme-template>
<portlet id="7_AESU3F5408QK30I4FE8ELO10O0">
<parameters>
<param name="test1">
<value>value1</value>
</param>
<param name="mode">
<value>download</value>
</param>
</parameters>
</portlet>
</state>
</root>
<atom:entry>
<atom:id>oid:7_AESU3F5408QK30I4FE8ELO10O0</atom:id>
<atom:title type="html">RemoteStateAndFragmentAPIViewPortlet</atom:title>
<atom:link portal:rel="window-state"
href="?uri=fragment:pm:oid:7_AESU3F5408QK30I4FE8ELO10O0@oid:6_AESU3F5408QK30I4FE8ELO1000&ibm.web2.normalizeState=true&javax.portlet.WindowState=maximized"
rel="related" type="application/xml" title="maximized" />
<atom:link portal:rel="window-state"
href="?uri=fragment:pm:oid:7_AESU3F5408QK30I4FE8ELO10O0@oid:6_AESU3F5408QK30I4FE8ELO1000&ibm.web2.normalizeState=true&javax.portlet.WindowState=minimized"
rel="related" type="application/xml" title="minimized" />
<atom:content type="html">
<![CDATA[
<div>
<h3 style="margin-bottom: 3px">Remote State and Fragment API View Portlet</h3>
Render parameters:
<table>
<tr>
<td>test1</td>
<td>value1</td>
</tr>
</table>
</div>
...
]]>
</atom:content>
<state-vary xmlns="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portal-state-vary">
<expr>state:root/state:state/state:portlet[@id='7_AESU3F5408QK30I4FE8ELO10O0']</expr>
<expr>state:root/state:state/state:shared-parameters[@id='global']/state:shared-parameter[@nsuri='http://RemoteStateAndFragmentAPIViewPortlet/']
[@localpart='TestPublicRenderParam']</expr>
</state-vary>
</atom:entry>
</atom:feed>
To give more practical insight in the usage of the previously described services, this documentation also provides a code sample realized by two portlets. You can download the sample code
as a Rational Application Developer 7.5 project interchange archive.
The RemoteStateAndFragmentAPIViewPortlet gives information whether the previous request contained an action, shows all render parameters that are currently set for the portlet, and provides a couple of sample URLs you can use to test and explore the decoding with the remote state service.
The RemoteStateAndFragmentAPIExplorePortlet contains JavaScript code that uses the remote state service to either decode the state information from a URL, or encode a given state XML document to a URL with the POST or GET method. Additionally, the portlet gives a usage example of the fragment service: When you paste a correct combination of a portal URL as well as page and portlet window identifiers, the portlet displays the markup fragment of the addressed portlet in a dedicated area.
The portlets have been developed as portlet projects in Rational Application Developer 7.5. The main JavaScript logic that controls the service interactions is contained in the RemoteStateAndFragmentAPIExplorePortletView.jsp of the RemoteStateAndFragmentAPIExplorePortlet. You can find more detailed information and implementation hints in the source code comments of the portlet project.
This description assumes that the RemoteStateAndFragmentAPIViewPortlet is placed on a page called “Sample View”, and the RemoteStateAndFragmentAPIExplorePortlet is placed on a page called “Sample Explorer”.
First navigate to the “Sample View” page and copy the “Render URL with parameter test1/value1” from the input field:
Then navigate to the “Sample Explorer” page, paste the previously copied URL to the Portal URL input field, and click “Decode State from URL”:
To try the different methods to encode the very same state XML representation back to a portal URL, you can clear the Portal URL input field and click the “Encode State to URL (POST)” or “Encode State to URL (GET)” buttons. Once the URL shows up in the input field, you can navigate to that URL by clicking the “Navigate to URL” button.
The state XML representation also gives the identifiers for the page and portlet window needed for the portlet fragment service. Starting from the previously used state, copy the selection-node to the “Page ID or Unique Name” input field, and the portlet id to the “Portlet Window ID or Unique Name” input field. Make sure that the correct URL is contained in the “Portal URL” input field. Then click on the “Get Portlet Fragment” button to get the portlet markup of the sample view portlet displayed in the section surrounded by “Portlet Fragment Display Area”:
You can now go ahead and test some advanced use cases like encoding an action URL to the portlet, trigger a new portlet fragment request and verify that the portlet fragment section correctly shows that an action has been performed.