URL generation services

Learn about the services used to create URLs in the navigational state SPI.

The Navigational State SPI offers the following two services that create URLs that are accessible via the Java Naming and Directory Interface (JNDI):

Both services use a common interface called com.ibm.portal.state.service.StateManagerService, which provides the functions that are common to both services. You can reuse URL generation code in themes, skins, and portlets if they use the common interface. For example, you can use a custom JSP tag, which was originally designed for use in themes, in a portlet-specific JSP because only the service lookup is different.


Get access to the PortalStateManagerService

Access the PortalStateManagerService through a JNDI lookup using the lookup name “portal:service/state/PortalStateManager”. The lookup returns a com.ibm.portal.state.service.PortalStateManagerServiceHome interface that provides the following two get commands that retrieve com.ibm.portal.state.service.PortalStateManagerService:

PortalStateManagerService getPortalStateManagerService( HttpServletRequest request, HttpServletResponse response)

PortalStateManagerService getPortalStateManagerService( ServerContext ctx, Locale locale, Profile profile, boolean isProtected, boolean isSecure)

The lifetime of a PortalStateManagerService object depends on whether you requested a “request-specific” service or “offline” service. The request-specific service has request scope; it is only used for the duration of one servlet request. For all subsequent servlet requests, request a new service instance from the home interface. The lifetime of the offline PortalStateManagerService corresponds with the lifetime of the ServerContext object.

The obtained PortalStateManagerServiceHome object is valid for the lifetime of the portal. You should perform the JNDI lookup only once and store the retrieved home object accordingly, for example in an instance or static variable.

The following example shows how to get access to the service:

/** the JNDI name to retrieve the PortalStateManagerServiceHome object */
private static final String JNDI_NAME = 
  "portal:service/state/PortalStateManager";
 
/** PortalStateManagerServiceHome object to retrieve the service from */
private static PortalStateManagerServiceHome serviceHome;
 
public void useRequestService(final HttpServletRequest request,
                              final HttpServletResponse response) {
  try {
    // get the request-specific service from our home interface
    final StateManagerService service
      = getServiceHome().getPortalStateManagerService(request, response);
    // use the service
    // ...
    // indicate that we do not need it any longer
    service.dispose();
  } catch (Exception e) {
    // error handling
  }
}
 
public void useOfflineService(final ServerContext ctx,
                              final Locale locale,
                              final Profile profile,
                              final boolean prot,
													 final boolean secure) {
  try {
    // get the offline service from our home interface
    final StateManagerService service
      = getServiceHome().getPortalStateManagerService(ctx, locale, profile, prot, secure);
    // use the service
    // ...
    // indicate that we do not need it any longer
    service.dispose();
  } catch (Exception e) {
    // error handling
  }
}
 
/**
 * Looks up the PortalStateManagerServiceHome being valid
 * for the lifetime of the portal.
 */
private static PortalStateManagerServiceHome getServiceHome() {
  if (serviceHome == null) {
    try {
      final Context ctx = new InitialContext();
      serviceHome =
        (PortalStateManagerServiceHome) ctx.lookup(JNDI_NAME);
    } catch (Exception e) {
      // error handling
    }
  }
  return serviceHome;
}
The PortalStateManagerService interface is derived from the generic StateManagerService interface. As the StateManagerService extends the com.ibm.portal.Disposable interface, you should indicate when you do not need to access the service any longer by invoking the offered dispose() method on it. Dispose the request-specific PortalStateManagerService by the end of the processed servlet request.


Get access to the PortletStateManagerService

Access the PortletStateManagerService via JNDI using the lookup name "portletservice/com.ibm.portal.state.service.PortletStateManagerService". The lookup returns a generic com.ibm.portal.portlet.service.PortletServiceHome interface which offers a getPortletService(Class) method to get the PortletStateManagerService. The retrieved PortletStateManagerService instance is valid for the lifetime of the portal. You should perform the service retrieval in the init method of the portlet and store it in a portlet instance variable. The following example shows the required lookup code:

public class MyPortlet extends GenericPortlet {
 
  /** The JNDI name which is needed to lookup the service */
  private static final String JNDI_NAME =
    "portletservice/com.ibm.portal.state.service.PortletStateManagerService";
 
  /** portlet state manager service */
  protected PortletStateManagerService service;
 
  /**
   * @see javax.portlet.GenericPortlet#init()
   */
  public void init() throws PortletException {
    super.init();
    try {
      // lookup the portlet state manager service
      final Context ctx = new InitialContext();
      final PortletServiceHome serviceHome = (PortletServiceHome) 
        ctx.lookup(JNDI_NAME);
      service = (PortletStateManagerService) 
        serviceHome.getPortletService(PortletStateManagerService.class);
    } catch (NameNotFoundException e) {
      throw new PortletException(e);
    } catch (NamingException e) {
      throw new PortletException(e);
    }
  }

You can use the actual service within the render method of the portlet (or in the helper methods serving the mandatory portlet modes such as doView, doEdit, and doHelp) to include URLs into the markup or in the processAction method in order to send a redirect to a certain URL. The PortletStateManagerService interface exposes the following two methods:
PortletStateManager getPortletStateManager( PortletRequest request, PortletResponse response)


PortletStateManagerController getPortletStateManagerController( ActionRequest request, Action response)

Both the PortletStateManager and the PortletStateManagerController have request scope, which means that not store references to them across requests. Instead retrieve the service from the PortletServiceHome object. To indicate that the retrieved PortletStateManager or PortletStateManagerController instance is no longer accessed in the scope of a request, invoke the dispose method inherited from the Disposable interface on it. The following example shows you how to retrieve the service from the PortletServiceHome object:

/**
 * @see javax.portlet.GenericPortlet#doView(RenderRequest, RenderResponse)
 */
protected void doView(
  final RenderRequest request, final RenderResponse response)
  throws PortletException, IOException {
  response.setContentType(request.getResponseContentType());
  final PrintWriter writer = response.getWriter();
  try {
    // get the request-specific portlet state manager
    final PortletStateManager mgr = service.
      getPortletStateManager(request, response);
    // do something (create URLs etc.)
    // ...
    // indicate that we do not need the portlet state manager any longer
    mgr.dispose();
  } catch (StateException e) {
    throw new PortletException(e);
  }
}


The base interface StateManagerService

The PortletStateManager and the PortalStateManagerService are derived from the com.ibm.portal.state.service.StateManagerService interface, which offers functionality that is common to both URL generation services. The use cases that are common to both services refer to the creation of EngineURLs that carry navigational state and resource URLs. Therefore, the StateManagerService interface should be sufficient to implement most of the use cases. The interface provides the following two methods:
URLFactory getURLFactory()


AccessorFactory getAccessorFactory(Class accessorFactoryClass)

Typically, you request an EngineURL object from the URLFactory and then modify the navigational state according to the required URL semantics. To perform this step, call the getState() method of the EngineURL to get the StateHolderController object that is required to modify the navigational state via the Accessor SPI. The following code snippet exemplarily illustrates this typical usage pattern. The following example shows how to call the getState() method of the EngineURL:

protected EngineURL createPageLink(final ObjectID pageID)
  throws StateException {
  // get the URL factory from the state manager service
  final URLFactory urlFactory = service.getURLFactory();
  try {
    // get a EngineURL from the factory; maintain navigational state
    final EngineURL url = urlFactory.newURL(null);
    final SelectionAccessorFactory selectionFct = (SelectionAccessorFactory) 
      service.getAccessorFactory(SelectionAccessorFactory.class);
    // get a selection controller that operates on the URL-specific state
    final SelectionAccessorController selectionCtrl = 
      selectionFct.getSelectionAccessorController(url.getState());
    try {
      // modify page selection and return URL
      selectionCtrl.setSelection(pageID);
      return url;
    } finally {
      selectionCtrl.dispose();
    }
  } finally {
    urlFactory.dispose();
  }
}

In the above code sample, the newURL(Constants.Clone) method of the URLFactory is used. However, the URLFactory offers several additional convenience methods to create EngineURLs as well as resource URLs. The following list provides a complete description of the URLFactory interface:

EngineURL newURL(Constants.Clone type)

EngineURL newURL(StateHolder state, Constants.Clone type)

EngineURL newURL(URLContext ctx, Constants.Clone type)

EngineURL newURL(URLContext ctx, Constants.Clone type)

DisposableURL newResourceURL( String name, PortalResources.Type type)

DisposableURL newResourceURL( String name, PortalResources.Type type, PortalResources.State state)

An absolute URL is a complete URL containing protocol, host name and port. In the case of a server-relative URL, the browser implies the current protocol, host name and port. In the case of a relative URL, the browser appends the URL to either the current request URL or to the value of the HTML base tag (if any). Server-relative and relative URLs cannot be enforced. In case of a protocol switch from “http” to “https”, for example, the generated URL is absolute in any case.


Change the host name of absolute URLs

You can change the host name of absolute URLs for security reasons. For example, this can be the case if the DOM of an application, such as a portlet, runs within an iframe and you do not want the JavaScript code within that iframe to be able to access the DOM of the HTML document itself. If all URLs within that iframe are absolute URLs and the host name of these URLs is different from the one from which the document originates, then the iframe has access to itself only. In other words, it can neither manipulate nor access the rest of the document DOM. To ensure this, create all URLs within the portlet by using the Navigational State SPI with absolute URLs. The portlet should then define a virtual host name, which must be rerouted by a proxy to the portal server again. In addition the portlet must ensure that all requests in which the required absolute URLs are to be generated contain a special request header that tells the portal the name of the virtual host name. The headers are as follows:
com.ibm.lotus.openajax.virtualhost


com.ibm.lotus.openajax.virtualport


Parent

Navigational State SPI

 


+

Search Tips   |   Advanced Search