Creating a content page resolution filter class | HCL Digital Experience

A content page resolution filter is used to customize the behavior of the content page resolution filter chain. This method is used to tailor the response to a web content request in several ways, including overriding the content item that is displayed or the portal page that is used to display a content item in the web content viewer.

About this task

The content page resolution filter chain is composed of filters that are based on the Intercepting Filter design pattern, which provides a mechanism for intercepting a request and manipulating the request and its response. When used with requests for web content, the content page resolution filter chain has default filters that process any URL parameters that are contained in the web content request and then determine which portal page has a matching web content association. The default filters occur at the end of the filter chain.

You can customize the content page resolution filter chain by creating custom filters that are registered with the portal through the Eclipse plug-in framework with the extension ID com.ibm.workplace.wcm.api.ContentPageResolutionFilter. The sequence of filters in the filter chain is specified by a weight value associated with each filter. To insert custom filters into the filter chain before the default filters, you can use the weight attribute in the plugin.xml file. If the weight attribute is not present, filter sequence is determined by the getFilterChainWeight method of each custom filter.

Custom filters can perform various actions:
  • Modify parameters before calling the default filters.
  • Modify the result of the default filters.
  • Handle exceptions that are generated by the default filters.
  • Determine whether the default filters are started.
  • Modify the content path that is used as input for the default filters.
  • Explicitly set a target page for displaying content.
  • Determine which web content page are used, if the default filters find more than one matching web content page for the request.
  • Modify the presentation template selection.
  • Set HTTP response status codes.
  • Send redirects to external web resources.

To use a content page resolution filter, you must create a content page resolution filter class and then register the filter by deploying it on the server.

Note: The resolve method can be called for every WCM POC "?urile=wcm:path:contentPath" request before the portal state and render parameters are set. It can then be used to change the contentPath and set the specific portal page to show the content one. Refer to the following Help Center documentation for additional information: Writing links to web content

Procedure

  1. Create a java class that implements the interface com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter. This class must implement the following methods:
    public int getFilterChainWeight() {}
    This method returns the weight that is applied to the content page resolution filter elements in the filter chain. The less it is weighted, the earlier the filter is inserted into the chain.If the weight parameter is defined in the plugin.xml file, that value overrides the value that is returned by this method.
    public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain) {}
    This method is started during ContentPageResolution processing. The response parameter is used to modify the content item that is displayed, the portal page where the content is displayed, and the presentation template that is used to render the content item. The request extends the resolver interface with an extra method that gets the content item that is addressed. The filter chain contains the subsequent filters that can be started if needed.

    See the Javadoc documentation for further information. The Javadoc files for Web Content Manager are in the PortalServer_root/doc/Javadoc/spi_docs/com/ibm/workplace/wcm directory.

  2. A plugin.xml file is needed whether the deployment is done by using a WAR or EAR, or by using a loose jar. If deploying with an application in a WAR or EAR, include the plugin.xml file in the application's "WEB-INF" folder. When using a jar, include the plugin.xml in the root of the jar.
    <?xml version="1.0" encoding="UTF-8"?>
    <plugin id="com.example"
           name="Sample Content Page Resolution Filter"
           version="1.0.0"
           provider-name="IBM">
           
     <extension
        point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
        id="SampleContentPageResolutionFilter">
        <provider class="com.example.SampleContentPageResolutionFilter"
                  weight="1"/>
     </extension>
    
    </plugin>
    When creating plug-ins, note the following:
    • Each plug-in is represented by a single <extension> tag.
    • The value of the extension point attribute must be com.ibm.workplace.wcm.api.ContentPageResolutionFilter.
    • Provide an ID value of your choice.
    • Specify the filter class for your plug-in.
    • The weight parameter overrides the value of the getFilterChainWeight method.
    Naming conventions:
    If you create a new plug-in application with the same names and IDs as an existing plug-in, the new plug-in can override the first. When creating plug-in applications ensure that the following are unique across your system:
    • The plug-in ID, plug-in name, and extension ID of the plugin.xml file.
    • The fully qualified class name and path of all classes within the application.
    • The file path of any files within the application.

Examples

  • The LocaleDependantSelectionFilter example performs the default page resolution and selects a target page from the candidate pages, according to the user's locale.
    package com.ibm.workplace.wcm.extension.resolution;
    
    import java.util.List;
    import java.util.Locale;
    
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    
    import com.ibm.portal.ObjectID;
    import com.ibm.portal.model.CorLocalizedContextHome;
    import com.ibm.portal.model.LocalizedContext;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilterChain;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionRequest;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionResponse;
    import com.ibm.workplace.wcm.api.extensions.resolution.exceptions.ContentPageResolutionException;
    
    public class LocaleDependantSelectionFilter implements ContentPageResolutionFilter
    {
       CorLocalizedContextHome localizedContextHome;
       
       public LocaleDependantSelectionFilter()
       {
          try
          {
             InitialContext ctx = new InitialContext();
             localizedContextHome = (CorLocalizedContextHome) ctx.lookup(CorLocalizedContextHome.JNDI_NAME);   
          }
          catch(NamingException e)
          {
             e.printStackTrace();
          }
       }
    
       public int getFilterChainWeight()
       {
          return 2;
       }
    
       public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain)
             throws ContentPageResolutionException
       {
          // do standard resolution first
          chain.resolve(request, response);
          
          // check if more than one candidate pages
          List<ObjectID> candidates = response.getCandidatePageIds();
          if (candidates.size() > 1)
          {
             LocalizedContext context = localizedContextHome.getLocalizedContext(request.getContext());
             Locale locale = context.getPreferredSupportedLocale();
             String lang = locale.getLanguage();
             // find page with matching unique name
             for (ObjectID pageId : candidates)
             {
                if (pageId.getUniqueName().endsWith("." + lang))
                {
                   response.setPageID(pageId);
                   break;
                }
             }
          }
       }
    }
  • The ChangeContentPathFilter example overrides the path of the content that is rendered but the page resolution is performed on the originally requested content.
    package com.ibm.workplace.wcm.extension.resolution;
    
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilterChain;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionRequest;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionResponse;
    import com.ibm.workplace.wcm.api.extensions.resolution.exceptions.ContentPageResolutionException;
    
    public class ChangeContentPathFilter implements ContentPageResolutionFilter
    {
       public int getFilterChainWeight()
       {
          return 3;
       }
    
       public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain)
             throws ContentPageResolutionException
       {
          // resolve page using requested content 
          chain.resolve(request, response);
          
          // but instead of england render UK
          if ("countries/world/europe/england".equals(response.getContentPath()))
          {
             response.setContentPath("countries/world/europe/uk");
          }
       }
    }
  • The ResolveToSpecificPageFilter example resolves to a specific page. No default resolution is performed in this case.
    package com.ibm.workplace.wcm.extension.resolution;
    import java.util.Arrays;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import com.ibm.portal.ObjectID;
    import com.ibm.portal.identification.Identification;
    import com.ibm.portal.serialize.SerializationException;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilterChain;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionRequest;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionResponse;
    import com.ibm.workplace.wcm.api.extensions.resolution.exceptions.ContentPageResolutionException;
    
    public class ResolveToSpecificPageFilter implements ContentPageResolutionFilter
    {
       private Identification identification;
       
       public ResolveToSpecificPageFilter()
       {
          try
          {
              InitialContext ctx = new InitialContext();
              identification = (Identification) ctx.lookup("portal:service/Identification");
          }
          catch (NamingException nx)
          {
              nx.printStackTrace();
          }
       }
    
       public int getFilterChainWeight()
       {
          return 4;
          }
    
    
     public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain) throws ContentPageResolutionException
    
     {
    
          try 
          {
          // always resolve to page with unique name my.default.page
          ObjectID pageId = identification.deserialize("my.default.page");
          response.setPageID(pageId);
          response.setCandidatePageIds(Arrays.asList(new ObjectID[]{pageId}));
          } 
          catch (SerializationException e)
          {
              throw new ContentPageResolutionException(e);
          }
      }
    }
  • The SetResponseCodePageResolutionFilter example checks for the requested web content item. If it does not exist, the code throws an exception that results in sending a 404 (Not found) HTTP response status code. If the content exists, resolution is delegated to other filters in the chain.
    package com.ibm.workplace.wcm.extension.resolution;
    
    import java.util.Arrays;
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Locale;
    import java.util.Set;
    import javax.servlet.http.HttpServletResponse;
    import com.ibm.portal.ListModel;
    import com.ibm.portal.LocalizedStatus;
    import com.ibm.portal.ModelException;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilterChain;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionRequest;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionResponse;
    import com.ibm.workplace.wcm.api.extensions.resolution.ResolvedItem;
    import com.ibm.workplace.wcm.api.extensions.resolution.exceptions.ContentPageResolutionException;
    
    public class SetResponseCodePageResolutionFilter implements ContentPageResolutionFilter
    
    {
    	 public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain) throws ContentPageResolutionException
      {
          if (!itemExists(request.getItem()))
          {
    			       // send 404
    			       throw new ContentPageResolutionException(new ContentNotFoundException());
          } 
    		   else
    		   {
    			      // forward to the chain if the web content exists
    			      chain.resolve(request, response);
    		   }
    	}
    
    	private boolean itemExists(ResolvedItem item)
    	{
           		return (item.getItemID() != null) && (item.getItemPath() != null);
    	}
    	public int getFilterChainWeight()
    	{
    	        	return 1;
    	}
    
    	private static class ContentNotFoundException extends Exception implements LocalizedStatus
    	{
           		private static final long serialVersionUID = 70L;
           		private static final Set<Locale> SUPPORTED_LOCALES = new HashSet<Locale>(Arrays.asList(new Locale[] { Locale.ENGLISH }));
     		private static final String MESSAGE = "The requested web content does not exist"; 
    
     		public ContentNotFoundException()
      		{ 			
                  super(MESSAGE);  		
         } 		 		
         
         public int getStatus()
      		{ 			
                 return HttpServletResponse.SC_NOT_FOUND;
      		}  		
         public String getTitle(Locale locale)
      		{  			
                  return MESSAGE; 		
         }   		
         public String getDescription(Locale locale)  		
         {  			
                  return MESSAGE;  		
         }  		
         public ListModel<Locale> getLocales()  		
         { 			
                  return new ListModel<Locale>()
                  {  				
                          public Iterator<Locale> iterator() throws ModelException
                          {
                                   return SUPPORTED_LOCALES.iterator();
                          }
                  };
        	}
       }
      }
  • The SendRedirectPageResolutionFilter example checks for the requested web content item. If the content does not exist, the code sends a redirect to http://www.ibm.com. If the content exists, the resolution is delegated to other filters in the chain.
    package com.ibm.workplace.wcm.extension.resolution;
    
    import java.io.UnsupportedEncodingException;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URLEncoder;
    import com.ibm.portal.resolver.exceptions.ResolutionException;
    import com.ibm.portal.resolver.helper.CORResolutionService;
    import com.ibm.portal.state.exceptions.StateException;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilter;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionFilterChain;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionRequest;
    import com.ibm.workplace.wcm.api.extensions.resolution.ContentPageResolutionResponse;
    import com.ibm.workplace.wcm.api.extensions.resolution.ResolvedItem;
    import com.ibm.workplace.wcm.api.extensions.resolution.exceptions.ContentPageResolutionException;
    
    public class SendRedirectPageResolutionFilter implements ContentPageResolutionFilter
    {
    	// the URL to redirect to
    	private static final String URL = "http://www.ibm.com";
    
    	public void resolve(ContentPageResolutionRequest request, ContentPageResolutionResponse response, ContentPageResolutionFilterChain chain) throws ContentPageResolutionException
    	{
    		if (!itemExists(request.getItem()))
    		{
    			try
    			{
    				// encode to URL, this is important to prevent that the ':'
    				// character appears in the path
    				String encodedURL = URLEncoder.encode(URL, "UTF-8");
    				final URI redirectURI = new URI(com.ibm.portal.resolver.Constants.SCHEME_REDIRECT, encodedURL, null);
    				CORResolutionService.SINGLETON.resolve(request.getResolved(), redirectURI, request.getVerb(), request.getResolutionParameters(), request.getAcceptedBindings(),request.getContext());
    			} catch (UnsupportedEncodingException uenc)
    			{
    				// should never happens as long as UTF-8 is supported
    				throw new ContentPageResolutionException(uenc);
    			} catch (URISyntaxException e)
    			{
    				throw new ContentPageResolutionException(e);
    			} catch (StateException e)
    			{
    				throw new ContentPageResolutionException(e);
    			} catch (ResolutionException e)
    			{
    				// do not catch the resolution exception
    				// as this is used internally to trigger the redirect
    				throw new ContentPageResolutionException(e);
    			}
    		} else
    		{
    			chain.resolve(request, response);
    		}
    	}
    
    	private boolean itemExists(ResolvedItem item)
    	{
    		return (item.getItemID() != null) && (item.getItemPath() != null);
    	}
    
    	public int getFilterChainWeight() 
    	{
    		return 1;
    	}
    }
  • The following example provides the plugin.xml file that registers the previous sample filters.

    Registering all of these filters in one system is not recommended. The filters perform overlapping operations and are also exclusive in some cases. To use one of the filters in your system, remove the other unused filters in the plugin.xml file before deploying the file.

    <?xml version="1.0" encoding="UTF-8"?>
    <?eclipse version="3.0"?>
    <plugin
       id="com.ibm.workplace.wcm.extension.resolution"
       name="Content Page Resolution Filter"
       version="1.0.0"
       provider-name="IBM">
       
       <extension point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
           id="SendRedirectPageResolutionFilter">
           <provider class="com.ibm.workplace.wcm.extension.resolution.SendRedirectPageResolutionFilter"
                    weight="1"/>
       </extension>
    
       <extension point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
            id="SetResponseCodePageResolutionFilter">
            <provider class="com.ibm.workplace.wcm.extension.resolution.SetResponseCodePageResolutionFilter"
                    weight="1"/>
       </extension>
    
       <extension point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
          id="LocaleDependantSelectionFilter">
          <provider class="com.ibm.workplace.wcm.extension.resolution.LocaleDependantSelectionFilter"
                    weight="2"/>
        </extension>
    
       <extension point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
          id="ChangeContentPathFilter">
          <provider class="com.ibm.workplace.wcm.extension.resolution.ChangeContentPathFilter"
                    weight="3"/>
        </extension>
    
       <extension point="com.ibm.workplace.wcm.api.ContentPageResolutionFilter"
          id="ResolveToSpecificPageFilter">
          <provider class="com.ibm.workplace.wcm.extension.resolution.ResolveToSpecificPageFilter"
                    weight="4"/>
        </extension>
    </plugin>