URLs in WebLogic Portal 8.1: A Tutorial

by Subbu Allamaraju
02/07/2005

Abstract

One of the core responsibilities of the BEA WebLogic Portal 8.1 framework is to create URLs consistently and correctly so users can interact with various portlets within the context of a portal page. The purpose of this article is to show you the plumbing behind the URL creation process in WebLogic Portal. In this article, I will discuss how WebLogic Portal creates URLs, the different kinds of URLs that can be created, the APIs and layers behind URLs, and what happens to URLs when you offer or consume portlets using Web Services for Remote Portlets (WSRP). As we walk through the URL creation process, I will also highlight some best practices. After reading this article, you will be able to avoid most of the common pitfalls with URLs and be able to provide a consistent user experience with your portlets.

The Problem

Why is URL creation such a core responsibility of the WebLogic Portal? Why can't portlets create URLs just like you always create in HTML/JSP pages, as in the code sample below?

Click <a href="next.jsp">here</a> to continue.

When the user clicks on a link like this, one of the following things can happen:

  • The user will see the content of next.jsp without the portal page aggregating this content.
  • The user will see an error page with dreaded exception stack traces.
  • The user's browser will display a DNS or security error if the portal is using WSRP to invoke the portlet and the user is not allowed to interact with the WSRP Producer directly.

To avoid these, portlets must let WebLogic Portal create URLs. There are several reasons why portlets should delegate this responsibility to WebLogic Portal:

TIP: When you are creating portlets, do not assume anything about the structure of URLs. The actual structure is determined not only by the templates deployed in the portlet's web app but also by the Consumer, in the case of WSRP.
  • A portal is the gateway to access portlets - As users interact with portlets (say, by submitting a form or clicking on a link), the portal receives the user request, finds the portlet that is responsible for handling the request, and then invokes the portlet. The portal also offers additional services like personalization, entitlements, and so on. Therefore, portlet-created links must point to the portal and not to the portlet's JSPs, servlets, or page flows.

  • Portlets are decoupled from portals - Portlets are reusable units that can be aggregated into multiple portals and desktops. Portlets therefore cannot assume a lot about the URL to the portal page. The portal aggregating the portlet could be (a) local in the same web app, (b) in a different web app on the same server, or (c) physically remote. In cases (b) and (c), the portal can use WSRP to aggregate the portlet in a page. In fact, the same portlet could be aggregated into portal pages of these three types at the same time.

  • Portlets are not aware of deployment - More important, portlets cannot assume a lot about how they are deployed. The deployment details include proxy servers, domain names, ports, and so on. Portlets cannot assume anything about these.

When you delegate URL creation to WebLogic Portal, it can shield portlets from things such as portal page URLs, domain names, and proxy servers. Portal administrators and deployers can control these details without breaking any URLs in portlets.

If you are curious to see one way to create the above link (assuming that you are creating this link in a simple JSP portlet), here it is:

Click <a href="<render:jspContentUrl contentUri="next.jsp"/>">here</a> to continue.

Now let's examine the plumbing behind WebLogic Portal's URLs.

URL Templates

WebLogic Portal uses short URL snippets called "URL templates" to create URLs. These are not valid URLs and require further processing to be useful. To see what a URL template looks like, create a portal project, and check its WEB-INF directory. In this directory, you will notice a url-templates-config.xml file. This file contains a number of default URL templates. Each URL template looks something like this:

<url-template name="default">

     {url:scheme}://{url:domain}:{url:port}/{url:path}?{url:queryString}{url:currentPage}

</url-template> to continue.
TIP: You can replace any of the optional tokens with known values. For example, if you know that you are never going to access portal pages over HTTPS, you can replace "url:scheme" with "http" in all the URL templates.

You will notice that this file lists not just one but several templates. Before discussing why several templates are required, let's look into the structure of a URL template.

Anatomy of a URL Template

A URL template is a URL with one or more tokens. The tokens are predefined by WebLogic Portal, and, in the case of remote portlets, by the WSRP 1.0 specification. Each token is enclosed within braces ( {, }). When you use a URL template to create a URL, WebLogic Portal replaces these tokens with values either specified by URL APIs or JSP tags, or derived automatically from the way the portal is deployed.

Each URL template can have one or more of the following tokens:

  • url:scheme: This is an optional token and specifies the HTTP scheme required for accessing the URL. The value could either be "http" or "https." If a value is not specified for this token at the time of using the URL template, WebLogic Portal will use whatever scheme was used to generate the page that this template is used in. For example, if you use "https" to access a page that has a URL with a template, it will replace this token with "https."

  • url:domain: This is an optional token and specifies the name of the domain used to access the portal. In most cases, this will be the name of the domain of the proxy server deployed in front of WebLogic Portal. If a value is not specified for this token at the time the URL template is used, WebLogic Portal uses the value of getServerName() of the incoming HttpServletRequest.

  • url:port: This is an optional token and specifies the port number used to access the portal. In most cases, this will be the port number of the proxy server. If a value is not specified, WebLogic Portal uses the value of getServerPort() of the incoming HttpServletRequest.

  • url:securePort: This is an optional token and specifies the SSL port number used to access the portal. In most cases, this will be the SSL port number of the proxy server. If a value is not specified, WebLogic Portal obtains the value from the server/proxy configuration.

  • url:prefix: This is an optional token and must be specified if you are using a path prefix in your proxy server setup.

  • url:path: All URL templates must include this token. Depending on whether the page is part of a portal or a desktop, WebLogic Portal replaces this token with an appropriate value.

  • url:contextualPath: This token is optional and applies to URLs that refer to paths relative to the web app context root. An example is a link to an image or file relative to the context root of the web app.

  • url:queryString: All URL templates must include this token. WebLogic Portal uses a number of reserved query parameters and uses this token to substitute these query parameters. The actual value replaced depends on how and where this template is used. To find out more about these reserved query parameters, refer to the white paper on the WebLogic Portal framework.

  • url:currentPage: This is an optional token used to embed the current page label in the URL generated.

TIP: Remember to replace the url:prefix token with the path prefix value used to set up the proxy server.

The list of templates contained in the url-templates-config.xml file that is created when a portal project is created caters to most common development needs.

Types of URLs

WebLogic Portal uses three kinds of URLs:

  • Action URLs: These URLs can be used to submit user interactions (such as form submissions and query links) and can be created by any portlet.
  • Resource URLs: Resource URLs can be used to generate links to static content such as images, style sheets, JavaScript files, pdf files, and so on. These URLs can be created by any portlet.
  • Render URLs: Render URLs are a special type of URL used by Java (JSR168-compliant) portlets and remote (uses WSRP) portlets.

A bit later on we will discuss how you can create any of these types of URLs in your JSPs.

Referring back to the url-templates-config.xml file, you will notice that this file has two main sections. The first section defines a number of URL templates. The second section defines how Java and Page Flow portlets can use these templates.

Each url-template defined in this file has a name and a string value. No two URL templates can have the same name. The string value is the URL template string with one or more tokens.

The second section of this file defines one or more url-template-ref elements for Java and/or Page Flow portlets. These are used to specify the URL template to be used for a given kind of URL. For example, the following snippet specifies that the URL template named jpf-action should be used to create action URLs used in page flows and that the URL template named jpf-secure-action should be used to create secure action URLs in page flows:

 <jpf-url-templates>

   <url-template-ref type="action" name="jpf-action"/>

   <url-template-ref type="secure-action" name="jpf-secure-action"/>

   ...

</jpf-url-templates>

Using URL Templates

WebLogic Portal provides a number of ways to use the URL templates defined in the previous section.

Using URL Templates Explicitly

You can use com.bea.portlet.GenericURL and its subclasses to create URLs using URL templates. Here is an example:

 <% 

    ResourceURL url = ResourceURL.createResourceURL(request, response);

    url.setScheme("http");

    url.setDomain("my.domain.com");

    url.setPort(8001);

    url.setPathPrefix("/static");

    url.setTemplate("my-resource-template");

    url.setPath("/images/my.jpg");

%>

<img src="<%=url.toString()%>"/> 

This snippet uses a my-resource-template to create a link to an image. When executed, this JSP generates the following:

<img src="http://my.domain.com:8001/static/images/my.jpg"/>
TIP: Make sure the URL template you are using has a token for the corresponding setter method. If not, WebLogic Portal will ignore the call to the setter.

Note that the template must exist in the my-resource-template file for this to work. The template must also have a url:prefix token specified for it to be replaced by the setPathPrefix() method.

In place of com.bea.portlet.GenericURL or its subclasses, you can use the URL tags available in the render tag library to create URLs. For example, you can rewrite the above JSP snippet using the renderUrl JSP tag:

<%@ taglib uri="render.tld" prefix="render" %>

<img src="<render:resourceUrl port="8001" template="default-complete" 

      scheme="http" domain="my.domain.com" 

      pathPrefix="/static" path="/images/my.jpg"/> "/>

Note that all the framework skeleton JSPs use the render tags to create links to window mode/state buttons, links to pages, and so on.

Using URL Templates in Portlets

When you use Page Flow and Struts tags to create forms, links, and so on in Page Flow and Struts portlets, those JSP tags delegate URL creation to WebLogic Portal through URL rewriters. These URL rewriters use URL templates specified by jpf-url-templates to create URLs.

The portlet container in WebLogic Portal uses a similar approach for Java portlets. When you create javax.portlet.PortletURL objects, the portlet container uses java-portlet-url-templates specified in the url-templates-config.xml file. Here is an example:

<%

   PortletURL actionURL = renderResponse.createActionURL();

   PortletURL renderURL = renderResponse.createRenderURL();

%>

WebLogic Portal will use the URL templates of type "action" and "resource" respectively to generate string values of these two URLs.

URLs in Remote Portlets

When you consume remote portlets using WSRP, it is very important to make sure that markup returned by remote portlets refers to the portal (the WSRP Consumer). When the portlet is remote, the Consumer acts as the intermediary between the end user and the portlet deployed on the WSRP Producer. Often, the Producer may set up security policies that restrict direct end user access to resources deployed on the Producer. So, links created without using WebLogic Portal are more likely to fail when the portlets are remote.

The WSRP 1.0 specification specifies two methods for URL creation, "producer writing" and "consumer rewriting." Let's briefly examine these two methods.

Producer Writing

This method involves the following steps:

  • The Consumer sends a set of URL templates to the Producer. These URL templates are similar in structure to those discussed above but contain tokens specified by the WSRP 1.0 specification.
  • The Producer uses these URL templates to create URLs and returns the markup to the Consumer.
  • If required, the Consumer may further process the URLs such that the URLs refer to the Consumer.

Of these three steps, the third step depends on how the WSRP Consumer is implemented. In the case of the WebLogic Portal as the Consumer, Producer URL writing involves these steps:

  • WebLogic Portal uses a set of URL templates meant for remote portlets. These templates are declared in the url-templates-config.xml file along with other URL templates. The wsrp-producer-registry.xml in the WEB-INF directory of the portal web app specifies the names of URL templates that must be used for remote portlets. Notice the extra tokens present in these templates. For example, the wsrp-default template has tokens like {wsrp-interactionState}, {wsrp-navigationalState}, and {wsrp-mode}. The WSRP 1.0 specification dictates the meaning of these tokens.

  • The Producer uses these templates to create URLs. Note that the Producer need not be a WebLogic Portal. Other implementations can process these URL templates because these tokens are defined by the WSRP 1.0 specification.

  • WebLogic Portal aggregates the markup returned from the Producer without further processing.

When the WebLogic Portal is set up as a Producer, it uses the URL templates, just as it does when portlets are used locally. The only difference is that it uses the templates sent by the Consumer instead of those deployed locally on the Producer.

Here is an example. Let's assume that you deployed a Page Flow portlet using the following JSP:

 <%@ taglib uri="netui-tags-html.tld" prefix="netui"%>

 <netui:anchor action="next">Next</netui:anchor>

When you consume this portlet in WebLogic Portal Consumer, it sends the following SOAP request to get the markup of this portlet:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

  <soapenv:Body>

    <urn:getMarkup xmlns:urn="urn:oasis:names:tc:wsrp:v1:types">

      <urn:portletContext>

        <urn:portletHandle>portlet_1</urn:portletHandle>

      </urn:portletContext>

      <urn:runtimeContext>

        <urn:userAuthentication>wsrp:none</urn:userAuthentication>

        <urn:portletInstanceKey>portlet_1_2_1</urn:portletInstanceKey>

        <urn:namespacePrefix>portlet_1_2_1</urn:namespacePrefix>

        <urn:templates>

          <urn:defaultTemplate>

            http://localhost:7001/consumer/hello.portal?_nfpb=true&amp;

            _windowLabel=portlet_1_2_1&amp;_pageLabel=hello_page_2&amp;

            wsrp-urlType={wsrp-urlType}&amp;wsrp-url={wsrp-url}&amp;

            wsrp-requiresRewrite={wsrp-requiresRewrite}&amp;

            wsrp-navigationalState={wsrp-navigationalState}&amp;

            wsrp-interactionState={wsrp-interactionState}&amp;

            wsrp-mode={wsrp-mode}&amp;wsrp-windowState={wsrp-windowState}

          </urn:defaultTemplate>

          <urn:blockingActionTemplate>

            http://localhost:7001/consumer/hello.portal?_nfpb=true&amp;

            _windowLabel=portlet_1_2_1&amp;_pageLabel=hello_page_2&amp;

            wsrp-urlType=blockingAction&amp;wsrp-url={wsrp-url}&amp;

            wsrp-requiresRewrite={wsrp-requiresRewrite}&amp;

            wsrp-navigationalState={wsrp-navigationalState}&amp;

            wsrp-interactionState={wsrp-interactionState}&amp;

            wsrp-mode={wsrp-mode}&amp;wsrp-windowState={wsrp-windowState}

          </urn:blockingActionTemplate>

          <urn:renderTemplate>

            http://localhost:7001/consumer/hello.portal?_nfpb=true&amp;

            _windowLabel=portlet_1_2_1&amp;_pageLabel=hello_page_2&amp;

            wsrp-urlType=render&amp;wsrp-url={wsrp-url}&amp;

            wsrp-requiresRewrite={wsrp-requiresRewrite}&amp;

            wsrp-navigationalState={wsrp-navigationalState}&amp;

            wsrp-interactionState={wsrp-interactionState}&amp;

            wsrp-mode={wsrp-mode}&amp;wsrp-windowState={wsrp-windowState}

          </urn:renderTemplate>

          <urn:resourceTemplate>

            http://localhost:7001/consumer/resource?_windowLabel=portlet_1_2_1&amp;

            wsrp-urlType=resource&amp;wsrp-url={wsrp-url}&amp;

            wsrp-requiresRewrite={wsrp-requiresRewrite}

          </urn:resourceTemplate>

          <urn:secureDefaultTemplate>

            http://localhost:7002/consumer/hello.portal?_nfpb=true&amp;

            _windowLabel=portlet_1_2_1&amp;_pageLabel=hello_page_2&amp;

            wsrp-urlType={wsrp-urlType}&amp;wsrp-url={wsrp-url}&amp;

            wsrp-requiresRewrite={wsrp-requiresRewrite}&amp;

            wsrp-navigationalState={wsrp-navigationalState}&amp;

            wsrp-interactionState={wsrp-interactionState}&amp;

            wsrp-mode={wsrp-mode}&amp;wsrp-windowState={wsrp-windowState}

          </urn:secureDefaultTemplate>

          <urn:secureBlockingActionTemplate><![CDATA[

            https://localhost:7002/consumer/hello.portal?_nfpb=true&

            _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2&

            wsrp-urlType=blockingAction&wsrp-secureURL=true&

            wsrp-url={wsrp-url}&wsrp-requiresRewrite={wsrp-requiresRewrite}&

            wsrp-navigationalState={wsrp-navigationalState}&

            wsrp-interactionState={wsrp-interactionState}&

            wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}]]>

          </urn:secureBlockingActionTemplate>

          <urn:secureRenderTemplate><![CDATA[

            https://localhost:7002/consumer/hello.portal?_nfpb=true&

            _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2&

            wsrp-urlType=render&wsrp-secureURL=true&wsrp-url={wsrp-url}&

            wsrp-requiresRewrite={wsrp-requiresRewrite}&

            wsrp-navigationalState={wsrp-navigationalState}&

            wsrp-interactionState={wsrp-interactionState}&

            wsrp-mode={wsrp-mode}&wsrp-windowState={wsrp-windowState}]]>

          </urn:secureRenderTemplate>

          <urn:secureResourceTemplate>

            https://localhost:7002/consumer/resource?_windowLabel=portlet_1_2_1&amp;

            wsrp-urlType=resource&amp;wsrp-secureURL=true&amp;

            wsrp-url={wsrp-url}&amp;wsrp-requiresRewrite={wsrp-requiresRewrite}

          </urn:secureResourceTemplate>

        </urn:templates>

      <urn:runtimeContext>

      <urn:userContext xsi:nil="true" 

            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>

      <urn:markupParams>

        <urn:secureClientCommunication>false</urn:secureClientCommunication>

        <urn:locales>en-US</urn:locales>

        <urn:mimeTypes>text/html</urn:mimeTypes>

        <urn:mimeTypes>*/*</urn:mimeTypes>

        <urn:mode>wsrp:view</urn:mode>

        <urn:windowState>wsrp:normal</urn:windowState>

        <urn:clientData>

          <urn:userAgent>Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; 

             SV1; .NET CLR 1.1.4322; FDM)</urn:userAgent>

        </urn:clientData>

      <urn:markupCharacterSets>UTF-8</urn:markupCharacterSets>

    </urn:markupParams>

  </urn:getMarkup>

</soapenv:Body>

</soapenv:Envelope>

The main detail to notice in this request is the templates element. Before sending URL templates to any Producer, WebLogic Portal Consumer replaces all Consumer-specific tokens in URL templates, leaving only WSRP 1.0-specific tokens. It is the responsibility of the Producer to replace the WSRP 1.0-specific tokens. Note that the templates in the above message are broken among several lines for better readability.

In response to the above SOAP request, a WebLogic Portal Producer would return the following response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

  <soapenv:Body>

    <urn:getMarkupResponse xmlns:urn="urn:oasis:names:tc:wsrp:v1:types">

      <urn:markupContext>

        <urn:mimeType>text/html; charset=UTF-8</urn:mimeType>

        <urn:markupString><![CDATA[

          <a href="http://localhost:7001/consumer/hello.portal?_nfpb=true&

              _windowLabel=portlet_1_2_1&_pageLabel=hello_page_2&

              wsrp-urlType=blockingAction&wsrp-url=&wsrp-requiresRewrite=&

              wsrp-navigationalState=&

              wsrp-interactionState=_action%3D%252Fhello%252FHelloWorld%252Fbegin&

              wsrp-mode=&wsrp-windowState=">Next</a>

     ]]></urn:markupString>

        <urn:locale>en-US</urn:locale>

        <urn:requiresUrlRewriting>false</urn:requiresUrlRewriting>

      </urn:markupContext>

    </urn:getMarkupResponse>

  </soapenv:Body>

</soapenv:Envelope>
TIP: WebLogic Portal Producer can store URL templates in the HTTP session, and therefore WebLogic Portal Consumer sends URL templates once per session.

Note that the Producer used the blockingActionTemplate to create the link for the netui:anchor tag. As the portlet markup returned in this response is fully qualified, it does not need further processing on the Consumer side.

If you are interested in learning more about the contents of these SOAP messages, visit the OASIS WSRP TC home page, and download the latest version of the WSRP 1.0 Primer.

Consumer Rewriting

In this approach, the Consumer does not send URL templates, and it involves the following steps:

  • The Consumer makes a requests for the portlet markup. The request will not include URL templates.
  • The Producer creates links enclosed within special markers specified by the WSRP 1.0 specification.
  • The Consumer parses this markup and replaces the links within those markers with proper URLs.

For the above sample portlet, the Producer would return the response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

  <soapenv:Body>

    <urn:getMarkupResponse xmlns:urn="urn:oasis:names:tc:wsrp:v1:types">

      <urn:markupContext>

        <urn:mimeType>text/html; charset=UTF-8</urn:mimeType>

        <urn:markupString>Hello World 

           &lt;a href="wsrp_rewrite?wsrp-urlType=blockingAction&wsrp-secureURL=false

           &wsrp-interactionState=_action%3D%252Fhello%252FHelloWorld%252Fbegin/wsrp_rewrite">Begin

           &lt;/a></urn:markupString>

        <urn:locale>en-US</urn:locale>

        <urn:requiresUrlRewriting>true</urn:requiresUrlRewriting>

      </urn:markupContext>

    </urn:getMarkupResponse>

  </soapenv:Body>

</soapenv:Envelope>

Note that the href value of the link is enclosed with wsrp_rewrite? and /wsrp_rewrite markers. WebLogic Portal Consumer then parses the markup within these markers and creates a URL using the action URL template deployed on the Consumer.

TIP: If you are using WebLogic Portal as a Consumer, try setting up the Producer to use URL templates for better performance.

Producer Writing or Consumer Rewriting?

The main difference between these two methods of URL creation is the use of URL templates. The kind of templates that WebLogic Portal Consumer sends to Producers do not require further processing of the markup returned by the Producer. This method therefore performs better when the WebLogic Portal is used as a Consumer.

WebLogic Portal Producers (simple as well as complex) are set up by default to use Producer writing for URL generation. You can change this to use Consumer rewriting by updating the wsrp-producer-config.xml file under the WEB-INF directory of the Producer. Refer to WebLogic Portal documentation on WSRP for more details.

Conclusion

One of my goals in this article was to point out why URL creation is critical to providing a consistent user experience. When you use WebLogic Portal-provided APIs and JSP tags, Page Flow or Struts tags, or Java Portlet API or tags, the URL creation process relies on URL templates. WebLogic Portal has the ability to consume locally deployed templates as well as templates sent by remote Consumers. These features are designed so all links created can be controlled by URL templates that can be adjusted declaratively without code changes.

It is quite possible to reverse-engineer the structure of generated URLs and create links manually (that is, without using any WebLogic Portal APIs or tags). Such links may work in some limited situations but are likely to fail when deployment configuration changes or when you use WSRP. Here are some final guidelines. Always use the following to create links:

  • In framework skeleton JSPs and portlet JSPs: com.bea.portlet.GenericURL or its subclasses or URL tags in the render tag library
  • In Page Flow portlets: Page Flow HTML tags
  • In Struts portlets: Struts HTML tags
  • In Java Portlets: Java Portlet API or URL tags in the portlet tag library

Use URLs created without these tags at your own discretion. Such URLs may not always work.

References

Subbu Allamaraju is the driver behind portal federation, and in recent years, focusing on portal-related standards such as JSR286, JSR301 and WSRP.