Category Archives: WebSphere Portal

[Resolved] WebSphere Portal Bug: Clicking Any Button in Inline Editing Will Causes Chrome Scrollbar To Disappear

We have raised a PMR with IBM and they have provided us with a temporary workaround for CF9 and below (as of 18 Mar 2016). The full workaround should be in WebSphere Portal 8.5 CF10.

9 May 2016: We have confirmed that the bug has been resolved in WebSphere Portal 8.5 CF 10.

How to replicate the issue:

  • Ensure that your WebSphere Portal version is 8.5 CF9 and below
  • Ensure that your Chrome browser is up to date
  • Open any content that is long enough for the Chrome vertical scrollbar to appear in Inline Editing.
  • Click on any button and the Chrome scrollbar will disappear.

 

Below is IBM temporary workaround (as of 18 Mar 2016).

For WebSphere Portal 8.5 CF9 and below, modify the following files:

  • AuthoringUIView.jsp (<wp_profile>/installedApps/cellname/PA_WCM_Authoring_UI .ear/ilwwcm-authoring.war/jsp/html/AuthoringUIView.jsp)
  • dialogCloserLaunchPage.jsp ( <wp_profile>/installedApps/cellname/PA_WCM_Authoring_UI .ear/ilwwcm-authoring.war/jsp/html/dialogCloserLaunchPage.jsp)

with the following codes:


/*BEFORE: find the following lines */
dojo.addOnUnload(function() { 
 if (frameElement) { 
  frameElement.scrolling="no"; 
 } 
});

/*AFTER: change the code as follows */
dojo.addOnUnload(function() { 
 if (frameElement) { 
  if (i$.isChrome) { 
   frameElement.scrolling="auto"; 
  } else { 
   frameElement.scrolling="no"; 
  } 
 } 
}); 

There is an additional step for WebSphere Portal 8.5 CF8 and below:

  • Go to <PortalServer>/theme/wp.theme .modules/webapp/installedApps/ThemeModules.ear/ThemeModules .war/modules/dialog/js/.
  • Backup dialog_layer.js and dialog_layer.js.uncompressed.js.
  • Copy dialog_layer.js.uncompressed.js content to dialog_layer.js and modify the file with the following codes:

/*BEFORE: find the following lines */
// Don't display scrollbars until dialog content has loaded, this is set back to auto in onLoadFrame 
// Note: in chrome setting overflow style to hidden will not hide scrollbars 
f.setAttribute("scrolling","no");

/*AFTER: change the code as follows */
// Don't display scrollbars until dialog content has loaded, this is set back to auto in onLoadFrame 
// Note: in chrome setting overflow style to hidden will not hide scrollbars
if(i$.isChrome) { 
 f.setAttribute("scrolling","auto"); 
} else { 
 f.setAttribute("scrolling","no"); 
}

WebSphere Portal: Specify White and Black List for Web Application

If your SystemOut.log is throwing the following warning message, it means that you will need to specific white and black list for your custom web application:

[3/24/16 12:18:17:143 SGT] 0000027f AbstractReque W com.ibm.wps.resolver.resource.AbstractRequestDispatcherFactory matchesWebAppDefault(aResource) Servlet context [/WebApp] does not specify a blackwhite list when accessing resource [themes/html/dynamicSpots/custom/header.jsp], falling back to the default [[whitelist(null), blacklist(WEB-INF/.*)]]. Applications can define a custom list by adding the keys [com.ibm.portal.resource.whitelist] and [com.ibm.portal.resource.blacklist] to their web.xml deployment descriptor. For details see information for APAR PI47714 related to CVE-2014-8912 (Security bulletin: http://www.ibm.com/support/docview.wss?uid=swg21963226).

Add the following parameters to your web.xml and redeployed your application:

<web-app> 
...
<context-param>
 <description>A regular expression that defines which of the resources in the war file can be served by the portal res datasource.</description> 
 <param-name>com.ibm.portal.resource.whitelist</param-name> 
 <param-value>.*</param-value>
</context-param> 
<context-param>
 <description>A regular expression that defines which of the resources in the war file cannot be served by the portal res datasource.</description> 
 <param-name>com.ibm.portal.resource.blacklist</param-name> 
 <param-value>WEB-INF/.*</param-value>
</context-param>
... 
</web-app> 

How to Remove Sign Up Link in WebSphere Portal Theme?

20160229125

WebSphere Portal theme will show Sign Up link by default for anonymous users. We can remove the link by deleting “Anonymous Portal User” from USER SELF ENROLLMENT virtual resources Editor role.

Do the following steps to remove Sign Up Link in WebSphere Portal Theme:

  • Login to WebSphere Portal using your portal administrator account.
  • Go to Portal Administration page (http://<hostname>/Administration).
  • Go to “Access > Resource Permissions” and click on “Virtual Resources” (It should be on the 2nd page).
    20160229126
  •  Click on USER SELF ENROLLMENTAssign Access” button.
    20160229127
  • Click on EditorEdit Role” button.20160229128
  • Remove “Anonymous Portal User” from Editor Role.
    20160229130
  • Now logout to verify the changes. The Sign Up link should be remove for Anonymous Portal User now.20160229131

WebSphere Portal: Remove “/wps/portal” from URL

IBM has finally provides us a way to remove "/wps/portal" in WebSphere Portal *pops champagne*. Do take note that this only applies to WebSphere Portal v8.5 CF8 onwards.

Take note (as of WebSphere Portal v8.5 CF8): After you have successfully remove “/wps/portal”, the system will not be unable to locate all previous custom themes that you have created earlier. You will need to run xmlaccess manually to remove “/wps” from the theme context-path.
“EJPFD0097E: No theme was found to render the page. Navigate to Administration and assign a working theme to restore full function to your site.”

 

Do the following steps to remove “/wps/portal”:

  1. Start cw_profile. Open your cmd and go to <app_server>\ profiles\cw_profile\bin and type “startServer.bat server1“.
  2. Go to Configuration Wizard (http://<server_ip>:10200/ibm/wizard).
  3. Login in with admin ID for cw_profile profile.
  4. Click “Set Up a Stand-alone Server > Modify Site URLs for Search Engine Optimization” or “Set Up a Cluster > Modify Site URLs for Search Engine Optimization” depending on your environment type.
  5. Click on “URL Settings” and select “Yes” for “Do you want to modify or remove your context root” field blank. (as of WebSphere Portal v8.5 CF8) I would not remove navigation state information using this method as this will cause default portal 8.5 theme to lose its navigation state as well. A better method will be this.
  6. Click on the “Next” arrow.
  7. Key in the required admin information and leave “Context root” and “
  8. Click on “Start Configuration” button.
  9. Click on “OK” button.
  10. The wizard will pause at certain manual steps. Click on the “Instructions” link to follow through the manual configuration.
  11. Congrats! You have remove “/wps/portal” from the url!

 

IBM WebSphere Portal Woes

We have been working with IBM WebSphere Portal for almost 8 years (from version 6.0 to 8.5) and often we realized that there are some points that IBM sales personnel deliberately wouldn’t let you know.

Disclaimer: We are still happy with IBM WebSphere Portal.


Poor PMR (aka Service Request) support

They wouldn’t attempt to read and replicate the issue in their own environment on their first reply (despite how much information you have provided them).

For example, we had reported recently that the Top Left Edit Tools in WebSphere Portal v8.5 were not showing in the latest Chrome version (44.0.2403.125) and even pointed out that we had experienced similar issue with the portal provided in one of the IBM training workshops.

We were thinking that L2 should be able to replicate the issue easily as L2 just need to update his Chrome browser. We are wrong:

Didn’t mean to be mean but we have already tried our best to provide you as much information as we could and it is really difficult to get trace.log from client environment with all the red tapes involved. Plus in this case, all you need to do is to update your Chrome browser to the latest version:

Mystery resolved (once L2 decided to update his browser and escalated the issue):

 

WebSphere Portal – Error 404: EJCBD0006E: The resolution of a URI failed. Refer to the SystemOut.log for more detailed information.

If you encounter “Error 404: EJCBD0006E: The resolution of a URI failed. Refer to the SystemOut.log for more detailed information.” while clicking on Authoring UI portlet links (for example Select Workflow link as shown in the screenshot above) and your SystemOut.log is returning you:

[7/30/15 15:11:47:539 SGT] 00000124 ExceptionLogg W com.ibm.wps.logging.ExceptionLogger logThrowable An exception occurred: [EJCBC0009E: The entity [[ObjectIDImpl 'Z6_00000000000000A0BR2B300G10', CONTENT_NODE, VP: 16576, [Domain: rel], DB: C040-000000000000000080026B8B35008001]] could not be be found.]. Enable traces for [com.ibm.wps.logging.ExceptionLogger=all] to see the exception stack trace.
[7/30/15 15:11:47:543 SGT] 00000124 ResolvedPrepr I com.ibm.wps.resolver.portal.ResolvedPreprocessor process The resolution process failed, for more details enable tracing for [com.ibm.wps.resolver.portal.ResolvedPreprocessor=all].

 

This can be a issue with the “Web Content Authoring” page under Hidden Pages (Content Root > Hidden Pages > Web Content Authoring).

  1. Go to Administration > Portal User Interface > Manage Pages.
  2. Ensure that “Web Content Authoring” page is Active.
  3. Ensure that the particular user has a USER role for that page.

 

How to Create WebSphere Portal Custom Workflow Action?

IBM allows us to customize our own workflow action. It will comes in handy when you need the system to:

  • Insert/remove a reference database record whenever a content get published/expired
  • Send email notification to news subscribers whenever a news content get published
  • Customize the default WCM email notification message

Disclaimer: This article follows the steps listed in Creating a custom workflow action class and we have replaced WebContentCustomWorkflowService with WcmCustomWorkflowService. At this point, we can’t confirm if WcmCustomWorkflowService is the correct class replacement.

Steps to create your custom workflow action:

  1. Open your Eclipse or IBM® Rational® Application Developer and make sure Java EE developer tools add-on is installed.
  2. Click on File > New > Web Project.
  3. Key in your custom workflow project’s name. Select “Simple” as Project Templates and “Java EE” as Programming Model.
  4. Under Deployment tab, select “2.4” as Web module version and checked “Add project to an EAR“.
    Click on the “Finish” button.
  5. Create a java class that implements the interface com.ibm.workplace.wcm.api.custom.CustomWorkflowAction. This class is responsible for executing your codes.
    Note: In this example, we will only be doing System.out.println to prove that the custom workflow action works

    package xxx.xxx.xxx.cwf;
    
    import java.util.Date;
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    import com.ibm.workplace.wcm.api.Document;
    import com.ibm.workplace.wcm.api.WcmCustomWorkflowService;
    import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
    import com.ibm.workplace.wcm.api.custom.CustomWorkflowActionResult;
    import com.ibm.workplace.wcm.api.custom.Directive;
    import com.ibm.workplace.wcm.api.custom.Directives;
    
    public class NewsAlertSubscriptionAction implements CustomWorkflowAction {
    
     @Override
     public CustomWorkflowActionResult execute(Document doc) {
      // Put your customized trigger codes here
      System.out.println("Executing NewsAlertSubscriptionAction");
      String msg = "";
      InitialContext initCtx = null;
      WcmCustomWorkflowService customWorkflowService = null;
      CustomWorkflowActionResult result = null;
    
      try {
       initCtx = new InitialContext();
       customWorkflowService = (WcmCustomWorkflowService) initCtx.lookup(WcmCustomWorkflowService.JNDI_NAME);
      } catch (Exception e) {
        msg = " - System has encountered exception (do check logs).";
        e.printStackTrace();
      }
    
      // directive: indicate if the content should proceed to the next stage
      // Check out WCM Javadoc for more valid directives information
      Directive directive = Directives.CONTINUE;
      System.out.println(" - document:" + doc.getName());
      return customWorkflowService.createResult(directive, msg);
     }
    
     @Override
     public Date getExecuteDate(Document arg0) {
      return DATE_EXECUTE_NOW;
     }
    }
    
  6. Create a custom workflow action factory class that implements the interface com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory. This is the controller class, it is use to call the respective custom workflow actions.
    package xxx.xxx.xxx.cwf;
    
    import java.util.Locale;
    import com.ibm.workplace.wcm.api.Document;
    import com.ibm.workplace.wcm.api.custom.CustomWorkflowAction;
    import com.ibm.workplace.wcm.api.custom.CustomWorkflowActionFactory;
    
    public class XXXCustomWorkflowActionFactory implements CustomWorkflowActionFactory {
     String NEWS_ALERT_SUBSCRIPTION = "News Alert Subscription";
    
     @Override
     public CustomWorkflowAction getAction(String arg0, Document arg1) {
      if (arg0.equals(NEWS_ALERT_SUBSCRIPTION)) {
       return new NewsAlertSubscriptionAction();
      }
      return null;
     }
    
     @Override
     public String getActionDescription(Locale arg0, String arg1) {
      if (arg0.equals(NEWS_ALERT_SUBSCRIPTION)) {
       return "Send Email Alert to Subscribers";
      }
      return null;
     }
    
     @Override
     public String[] getActionNames() {
      String names[] = { NEWS_ALERT_SUBSCRIPTION };
      return names;
     }
    
     @Override
     public String getActionTitle(Locale arg0, String arg1) {
      return arg1;
     }
    
     @Override
     public String getName() {
      return "XXX Custom Workflow Actions";
     }
    
     @Override
     public String getTitle(Locale arg0) {
      return "XXX Custom Workflow Actions";
     }
    }
    
    
  7. Create a plugin.xml file if you are deploying using WAR or EAR. Include the plugin.xml file in the application’s “WEB-INF” folder.
    <?xml version="1.0" encoding="UTF-8"?>
    <plugin id="XXXCustomWorkflowActionsPlugin" name="XXX Custom Workflow Actions Plugin" version="1.0.0" provider-name="IBM">
    <extension point="com.ibm.workplace.wcm.api.CustomWorkflowActionFactory" id="XXXCustomWorkflowActionFactory">
    <provider class="xxx.xxx.xxx.cwf.XXXCustomWorkflowActionFactory"/>
    </extension>
    </plugin>
    
  8. Follow the Deploying custom plug-in applications to deploy your plugin.
  9. Go to Web Content Authoring portlet and create Custom Workflow Action, you should be able to select your custom workflow action as shown below.

 

WebSphere Portal 8.5: Customize Ephox Editor

Updates (6-Jul-2015): 
With Chrome (version 42) finally dropping support for NPAPI, we can only hope that Ephox Textbox.io can catch up with its predecessor - http://docs.ephox.com/display/IBMWCMTB/Textbox.io+for+IBM+WCM+Home.

We have been encouraging our clients to use Ephox Editor as their default WCM rich text editor ever since IBM has acquired Ephox Editor OEM licence. Hence it is important for us to know how to:

  • Customize Ephox Editor default menu and toolbar items (for example change the default font size from “pt” to “px”)
  • Apply our custom theme css classes styles in Ephox Editor

Most of the customization will be taking place at the config file, it is located at  <wp_profile>/installedApps/<cell>/wcm.ear/editor-editlive-config.war/config/config.xml.jsp.

 

Steps to customize Ephox Editor default editor settings:

  1. Read Setting Menu and Toolbar Items tutorial guide first.
  2. Edit the config file accordingly.
  3. Restart the server.

 

Steps to include custom theme css in Ephox Editor:

  1. Read Using CSS in the Applet tutorial guide first.
  2. Edit the config file accordingly.
  3. Restart server.

 

Query Service in WebSphere Portal WCM API

QueryService is a good addition to WCM API. It helps to keep the API neat and provides a way for developers to do “OR” condition (Disjunction class).

Below is a simple example on how to do a “Like” search on content’s title
(Do take note that Selectors.titleLike method is case-sensitive (as of 8.5) <- hope they will add in extra argument in future to allow us to decide if the title search should be case-sensitive)


Repository repository = WCM_API.getRepository();
Workspace ws = repository.getWorkspace();
ws.login();

QueryService queryService = ws.getQueryService();
Query query = queryService.createQuery(Content.class);
query.addSelector(Selectors.titleLike("%a%")); //searching for contents' title containing "a"

query.addSort(Sorts.byPublishDate(SortDirection.DESCENDING)); // sort by publish date
ResultIterator resultIter = queryService.execute(query);
while (resultIter.hasNext()) {
 Content content = (Content) resultIter.next();
 // process...
}

 

But we noticed that there are performance deficits when we try to traverse > 400 contents (~11 sec to complete). The deficit occurs when we tried to cast the object into its respective object types (for example (Content) resultIter.next()). We believe that the API is trying to clone the content’s internal document (including its respective elements).

Hence if you just need to reference the contents, perhaps you can try to retrieve content using the traditional Workspace.getById(DocumentId<T> id, boolean asReference, boolean loadElements) method (as this effectively reduce our time from 11 sec to just 1 sec on our side). Do let us know if it works for you, cheers!


Repository repository = WCM_API.getRepository();
Workspace ws = repository.getWorkspace();
ws.login();

QueryService queryService = ws.getQueryService();
Query query = queryService.createQuery(Content.class);
query.returnIds(); // get the query services to return DocumentId instead of Document objects
query.addSelector(Selectors.titleLike("%a%")); //searching for contents' title containing "a"

query.addSort(Sorts.byPublishDate(SortDirection.DESCENDING)); // sort by publish date
ResultIterator resultIter = queryService.execute(query);
while (resultIter.hasNext()) {
 Content content = (Content) ws.getById(((DocumentId) resultIter.next()),true,false); // only retrieve a reference Content without loading its elements
 // process...
}

 

Disjunction (Our favourite “OR” condition)

Below is a code snippet on how to retrieve contents based on “OR” categories condition (Disjunction).


Disjunction orCondForCats = new Disjunction();
// tranverse contents if they contains one of the selected categories
for (int i = 0, len = selectedList.size(); i &lt; len; i++) {
 orCondForCats.add(ProfileSelectors.categoriesContains(selectedList.get(i)));
}
query.addSelector(orCondForCats);

 

Conclusion:
We certainly will be using Query Service more often for our future projects. We also felt that the method has room  for improvements:

  • Provide a new execute method (similar to Workspace.getById(DocumentId<T> id, boolean asReference, boolean loadElements)) which allow developers to decide if the documents retrieve should be editable and loaded with elements. This should effectively improve the Query Service performance.
  • Provide an option to allow developers to perform case-insensitive search for content’s title.

WebSphere Portal EJPPD0015E: Portlet application manager failed

Scenario

You have created your portlet using RAD and deployed the portlet to WebSphere Portal. For some reasons, you need to remove the portlet (not update) and re-deployed the portlet again. Immediately you encountered “EJPPD0015E: Portlet application manager failed” exception in your SystemOut.log file.

Then you begin to trace and discover that the exception occurs at EMF2DOMAdapterImpl_ERROR_0:

Caused by: java.lang.IllegalStateException: EMF2DOMAdapterImpl_ERROR_0
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.handleInvalidMultiNodes(EMF2DOMAdapterImpl.java:1402)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.findDOMNode(EMF2DOMAdapterImpl.java:1389)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.primUpdateMOFFeature(EMF2DOMAdapterImpl.java:1572)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.updateMOFFeature(EMF2DOMAdapterImpl.java:1992)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.primUpdateMOF(EMF2DOMAdapterImpl.java:1010)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.updateMOF(EMF2DOMAdapterImpl.java:986)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.primUpdateMOFMultiFeature(EMF2DOMAdapterImpl.java:489)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.updateMOFRootFeature(EMF2DOMAdapterImpl.java:1039)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.primUpdateMOF(EMF2DOMAdapterImpl.java:1006)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMAdapterImpl.updateMOF(EMF2DOMAdapterImpl.java:986)
at org.eclipse.wst.common.internal.emf.resource.EMF2DOMRenderer.doLoad(EMF2DOMRenderer.java:331)
at org.eclipse.wst.common.internal.emf.resource.TranslatorResourceImpl.basicDoLoad(TranslatorResourceImpl.java:633)
... 78 more

If that is the reason, then you might just be in luck. Go to your WEB-INF/web.xml and ensure that the web.xml file does not contains multiple nodes of the following:

  • session-config
  • welcome-file-list
  • jsp-config
  • login-config
  • locale-encoding-mapping-list