After applying CF39 on 6.1.0.3, 6.1.0.4, 6.1.0.5 (PM25810) or 6.1.5.x (PM25794) WCM, the Ephox EditLive! editor does not load up

After applying CF39 on 6.1.0.3, 6.1.0.4, 6.1.0.5 (PM25810) or 6.1.5.x (PM25794) WCM, the Ephox EditLive! editor does not load up.

Symptoms :-

The primary symptom is when viewing a rich text element the following error is seen on the browser

JSP Processing Error
HTTP Error Code 500

Error Messages :-

JSPG0227E: Exception caught while translating /jsp/html/EditLiveJavaEditor.jsp:
/jsp/html/EditLiveJavaEditor.jsp(0,1) --> JSPG0005E: tld file could not be found for uri[/WEB-INF/tld/ilwwcm.tld] prefix [ilwwcm]

Root Cause :-

com.ibm.ws.jsp.translator.JspTranslationException: JSPG0227E: Exception caught while translating /jsp/html/EditLiveJavaEditor.jsp:
/jsp/html/EditLiveJavaEditor.jsp(0,1) --> JSPG0005E: tld file could not be found for uri[/WEB-INF/tld/ilwwcm.tld] prefix [ilwwcm]
at com.ibm.ws.jsp.translator.visitor.validator.ValidateVisitor.visitJspRootStart(ValidateVisitor.java:516)
at com.ibm.ws.jsp.translator.visitor.JspVisitor.processJspElement(JspVisitor.java:138)


Resolution :-

CF40 will resolve this issue. This should be installed on top of CF39.
Until CF40 is available, a downgrade to CF38 will resolve this issue

IBM Support Tools portlet for Lotus WCM

The IBM Support Tools portlet for Lotus WCM is useful to troubleshoot content related issues.

ClickHere to download Portlet from IBM Solution Catalog (Lotus GreenHous login required)

This portlet includes tools to view the JCR repository for WCM content, run an xpath query and view results, and directly execute various support jsps

Writing Custom Portlet Mode in WebSphere Portal



Steps
a.  Override generic portlet Dispatch method

private static final PortletMode CUSTOM_CONFIG_MODE = new PortletMode("config");
private static final PortletMode CUSTOM_EDIT_DEFAULTS_MODE = new PortletMode("edit_defaults");

protected void doDispatch(RenderRequest request, RenderResponse response) throws PortletException, IOException {
              if (!WindowState.MINIMIZED.equals(request.getWindowState())){
                     PortletMode mode = request.getPortletMode();                 
                     if (CUSTOM_CONFIG_MODE.equals(mode)) {
                           doCustomConfigure(request, response);
                           return;
                     }
                     else if (CUSTOM_EDIT_DEFAULTS_MODE.equals(mode)) {
                           doCustomEditDefaults(request, response);
                           return;
                     }
              }
              super.doDispatch(request, response);
       }

b. Add following in the portlet.xml

<custom-portlet-mode>
            <portlet-mode>config</portlet-mode>
      </custom-portlet-mode>
      <custom-portlet-mode>
            <portlet-mode>edit_defaults</portlet-mode>
</custom-portlet-mode>

Add following entries under the portlet tag
<supports>
      <portlet-mode>config</portlet-mode>
      <portlet-mode>edit_defaults</portlet-mode>
</supports>

Note: If a custom portlet mode defined in the deployment descriptor is not mapped to a custom portlet mode provided by WebSphere Portal, portlets must not be invoked in that portlet mode.  Ex: you can not create like "resize" mode for the portlet that deployed in websphere as websphere doesn't support it.

Making AJAX call using DWR (Direct Web Remoting)

This Article will explain how to make DWR (Direct Web Remoting) AJAX call from JSP

Follow the simple Steps
a         Copy the DWR jar file to the Lib directory under webcontent/WEB-INF (download from here)
b        Copy the following xml snippet to the web.xml
<servlet> 
<servlet-name>dwr-invoker</servlet-name>
<servlet-class>org.directwebremoting.servlet.DwrServlet</servlet-class>
<init-param>
                      <param-name>debug</param-name>
                      <param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dwr-invoker</servlet-name>
<url-pattern>/dwr/*</url-pattern>
</servlet-mapping>

c         Create or Copy the dwr.xml under the WEB-INF directory and content of the file is as follows
<!DOCTYPE dwr PUBLIC
    "-//GetAhead Limited//DTD Direct Web Remoting 2.0//EN"
    "http://getahead.org/dwr/dwr20.dtd">

<dwr>
  <allow>
    <create creator="new" javascript=" AjaxDWRTest">
      <param name="class" value="com.vaka.siva.helper.AjaxDWRTest"/>
    </create>
  </allow>
</dwr>

d        Write a class with public methods and className  should be like as specified in dwr.xml (If you need the  HTTPServletSession then we use below extra code)

public class AjaxDWRTest {
public String getDisplayedTickets(int pageIndex) {
                                               
                                                WebContext ctx = WebContextFactory.get();
                                                HttpServletRequest request = ctx.getHttpServletRequest();
                                                HttpSession session = ctx.getSession();
                                                if (session == null)return null;
                                               
//call to some helpers and do the processing
//you can make backend calls now or you can make backend calls first and store it in the session and now retrieve from session

return tktstr
}
e        In above XML , we have specified the AjaxDWRTest as javascript ,so DWR will create  that for us we just need to include the following in JSP where we need the AJAX call

<script type="text/javascript" src='<%= renderResponse.encodeURL(renderRequest.getContextPath()+ "/dwr/interface/AjaxDWRTest.js") %>'>
</script>
<script type="text/javascript" src='<%= renderResponse.encodeURL(renderRequest.getContextPath()+ "/dwr/engine.js") %>'>

f          Following is the way we invoke the callback method in JSP

//Print the table with initial values List (this is not ajax call)
<c:if test="${!empty SessionBean.initialTicketValuesMap}">
<script type="text/javascript">
               <portlet:namespace/>paintDynaSec(intialTicketValuesString);
</script>
</c:if>

//following is AJAX call , when somebody click next page then we call below
AjaxDWRTest.getDisplayedTickets(currentPageIndex, <portlet:namespace/>paintDynaSec);

//Once AJAX backend call is over then above statement will automatically calls paintDynaSec javascript function with parameter that is returned from the AJAX
function <portlet:namespace/>paintDynaSec(tktstr) {
                        ticketList.innerHTML =tktstr;
}

Making AJAX call using smiple XMLHTTPRequest Object

This Article will explain how to make simple AJAX call from JSP 

Follow the simple Steps 
a.         Create a servlet (can be any server side component that listen to requests and respond back like JSP or PHP).
b.       In JSP file, first get the XMLHttpRequest object (it is different for different browsers)
c.         onreadystatechange property: After a request send to a server, we need a function to receive the data returned from the server. The onreadystatechange property stores the function that will process the response from a server. The function is stored in the property to be called automatically.
xmlhttp.onreadystatechange=function()
{
// We are going to write some code here
}
d.        readyState property: The readyState property holds the status of the server's response each time the readyState property changes, the onreadystatechange function will be executed .Possible values for readyState property are
i           0 – request is not intialized
ii         1 – request has been setup
iii        2 – request has sent
iv       3 – request in progress
v         4 – request is completed
e.        To send off a request to the server, we use the open() and send() methods.
i           Open(): The open() method takes three arguments. The first argument defines which method to use when sending the request (GET or POST). The second argument specifies the URL of the server-side script. The third argument specifies that the request should be handled asynchronously(true – asynchronous , false – synchronous )
ii         Send: The send() method sends the request off to the server.
f.          Sample is as follows
//getting XMLHttpRequest Object
function getXMLHTTPObject(){
if(window.XMLHttpRequest){
return new XMLHttpRequest();
}
if(typeof XMLHttpRequest != 'undefined'){
   return new XMLHttpRequest();
}else{
  try{
  return new ActiveXObject("Msxml2.XMLHTTP");
  }catch(e){
  try{
          return new ActiveXObject("Microsoft.XMLHTTP");
  }catch(e){}
  }
}
 return false;
}
//make AJAX call
function invokeAjax(){
       xmlHTTP=getXMLHTTPObject();
       var ajaxServletURL="<%=response.encodeUrl(request.getContextPath())%>"+"/SivaAjaxServlet?name=siva";
       xmlHTTP.open("POST",ajaxServletURL,true);
       xmlHTTP.setRequestHeader ("Content-Type", "application/x-www-form-urlencoded");
       xmlHTTP.onreadystatechange=httpResponse;
       xmlHTTP.send(null);
}
 //callback method
function httpResponse(){
  if(xmlHTTP.readyState==4){
    document.getElementById("ajaxdiv").innerHTML=xmlHTTP.responseText;
  }
}
 //simple html elements gets change after ajax call
<div id="ajaxdiv">
 <table>
       <tr><td>Loading ....Ajax example</td><td><input type="button" onClick="invokeAjax()" name="but1" value="submit"/></td></tr>
 </table>
</div></div>


Invalidate the browser cache

Set the following response headers to invalidate any browser Cache.


response.setHeader("Pragma","no-cache"); 
response.setHeader("Cache-Control","no-cache, no-store, must-revalidate"); response.setHeader("max-age","0");  


Alternatively you can use the HTTP meta equivalent tags to do in HTML 

<meta http-equiv="Cache-Control" content="no-store,no-cache, must-revalidate,post-check=0, pre-check=0,max-age=0">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0"> 


Click Here for more options on cahce-control

Troubleshooting DataBase (DB) Performance Issues

At some point in any project implementation, need to troubleshoot the DB either to resolve the problem or performance.

Things to consider

1. Check the connection pool size
2. Fine Tune SQL statements
3. Execute  "UPDATESTATS" at DB side  to update the tablespace sizes and make updates to stats
4. Check the webserver I/O timeout , if it is very low (like 10sec) sometime you may receive the 500 (server timeout). HTTP server timeout should be aggregate of  considering DB response time + application response time
5. Considering the option of creating materialized view or MQT(materialized query table).

Setting Browser Titles for the WCM Content

There is simple way we can set the browser title for the Lotus Web Content Management Content, Add one of the following statements to all of your presentation templates


<script>
document.title='<Placeholder tag="name"/>';
</script>
or
<script>
document.title='<IDCmpnt context="current" type="content" field="name"/>';
</script>

Problems while working with elements (Nodes) in DOM (JavaScript) Dynamically.

Issue 1: setAttribute doesn't work for all elements in IE (but it works fine in Mozilla and Chrome)


var tableElement = document.createElement('table');
tableElement.setAttribute("id","tableID");
tableElement.setAttribute("name","tableName");
tableElement.setAttribute("className","CSSClasName");

Cross browser Solution for the above problem is use like below

var tableElement = document.createElement('table');
tableElement.id="tableId";
tableElement.name="tableName";
tableElement.className="CSSClassName";


Issue 2: calling onClick event(Javascript Functions) on elements created using createElement (dynamic DOM)


var upArrowButton=document.createElement("input");
upArrowButton.type="button";
upArrowButton.value="\u2191";
upArrowButton.onclick="moveElementUp();";

Above statements will call moveElementUp() method on onClick() Event in Mozilla and Chrome but it doesn't work in IE. To make it work across all the browsers use like below (anonymous function)

upArrowButton.onclick=function(){ moveElementUp(); };

Issue 3: removeChild() method need to call in reverse order to properly remove multiple element from parent Node


var textareaArray= document.getElementById('parentID').getElementsByTagName('textarea');
for(var x=0;x<hildren.length;x++){
document.getElementById('parentID').removeChild(textAreaArray[x])
}

Above statements may not work properly to remove text area child nodes of the "parentID",  while removing the remove always remove the last child first . Following for do the job

for(var x=textareaArray.length-1;x>=0;x--){
document.getElementById('parentID').removeChild(textAreaArray[x])
}


Issue 4: Issue while retrieving child nodes with document.getElementsByTagName method

var children = document.getElementById('parentID').getElementsByTagName('*');

"children" array in above statement will be all decedents of "parentID" not only direct childrens. To get the direct children use the following statement

var children = document.getElementById('parentID').childNodes; //this will return only direct decedents

Setting HTML entity values (↑ ) to DOM dynamically (createElement)

If you try to create and add the element to DOM as below , it doesn't take the HTML entity codes like "&uarr;" ,"&darr;" or char codes like  "&#8593;" .

instead of Arrow marks

var buttonEl = document.createElement('input');
buttonEl.type = 'button';
buttonEl.value = '&rarr;'


Above code will just display as 

To display actually up arrow and down arrows like below use the unique code corresponding to them like below

for up arrow
buttonEl.value = '\u2191'

for downarrow
buttonEl.value = '\u2193'

javascript cloneNode doesn't copy the event handlers

This article shows how to clone the javascript events along with node when we use the cloneNode method

javascript cloneNode do shallow copy, it doesn't copy the event handler attached to that node or it children. following method will help you to attach javascript events after cloning.



function cloneNodeWithEvents( orgNode ){

var orgNodeEvenets = orgNode.getElementsByTagName('*');
var cloneNode = orgNode.cloneNode( true );
var cloneNodeEvents = cloneNode.getElementsByTagName('*');

var allEvents = new Array('onabort','onbeforecopy','onbeforecut','onbeforepaste','onblur','onchange','onclick',
'oncontextmenu','oncopy','ondblclick','ondrag','ondragend','ondragenter', 'ondragleave' ,
'ondragover','ondragstart', 'ondrop','onerror','onfocus','oninput','oninvalid','onkeydown',
'onkeypress', 'onkeyup','onload','onmousedown','onmousemove','onmouseout',
'onmouseover','onmouseup', 'onmousewheel', 'onpaste','onreset', 'onresize','onscroll','onsearch', 'onselect','onselectstart','onsubmit','onunload');


// The node root
for( var j=0; j<allEvents.length ; j++ ){
eval('if( orgNode.'+allEvents[j]+' ) cloneNode.'+allEvents[j]+' = orgNode.'+allEvents[j]);
}

// Node descendants
for( var i=0 ; i<orgNodeEvenets.length ; i++ ){
for( var j=0; j<allEvents.length ; j++ ){
eval('if( orgNodeEvenets[i].'+allEvents[j]+' ) cloneNodeEvents[i].'+allEvents[j]+' = orgNodeEvenets[i].'+allEvents[j]);
}
}

return cloneNode;

}

JSR 286 Content Viewer Portlet vs IBM Content Viewer Portlet(till 6.0)

This Article describes differences between the IBM Content Viewer and JSR 286 version of Content viewer


IBM Content Viewer Portlet (till 6.0.1)
In the IBM Portlet API version of the viewer, you can simply add a query parameter to a URL addressing the page and all the IBM portlets on that page received that parameter. You then configured the portlet to listen to broadcasts and created a URL in the format:
http://[PORTAL_HOST]/[PORTAL_CONTEXT_ROOT]/[PORTAL_PAGE_URL_MAPPING]
/?WCM_GLOBAL_CONTEXT=<pathCmpnt type="noprefixservlet" />/[LIBRARY]/[SITE]
/[SITE_AREA_PATH]/[CONTENT]
 
http://mysystent/wps/portal/home?WCM_GOBAL_CONTEXT=/mynewslib/usnews/news1.
 
This portlet is simple to use, but it has the following drawbacks:
  • Since the parameter is not maintained in the URL, it needs to be stored in the session (even in the case of anonymous use) and therefore impacts portal server memory consumption.
  • Once you’ve interacted with the page and the parameter is no longer in the URL -- but stored in the session -- you can no longer bookmark your selection.
  • For static pages, caching in the browser doesn’t work because the selection is not encoded into the URL. This means the browser can’t distinguish between news item 1 and news item 2 and therefore cannot cache on the browser level.
The query parameter solution of the old IBM Portlet API has two disadvantages:
  • You only get the parameter for one request; after that each portlet on the page needs to store the value in the session. This requires having sessions even in the case of anonymous use.
  • You don't know what parameter a portlet understands, as the portlets don’t formally declare this. You can even run in a situation where two portlets define the same parameter name, but with different semantics that would prevent you from putting these two portlets onto the same page, and you wouldn’t know this beforehand.
JSR 286 Content Viewer Portlet


The Java Portlet Specification V 2.0 (JSR 286) defines something called a render parameter that is provided to the portlets for each request. For example, when the user presses the browser's reload button, the portlet gets the same render parameters again and can render the same view. This means that the portlet does not need to store this navigational state information in the session any longer

The fully qualified name of the public render parameter that is supported by the JSR 286 Web content viewer is http://www.ibm.com/xmlns/prod/datatype/content:context
Because you might have many public and private render parameters that you need to store in the URL, you need to make sure that the URLs don't get too long. WebSphere Portal does this by zip-encoding that part of the URL

If a specific parameter gets too large, it is stored in the session and only the reference key is stored in the URL. This helps to keep the URL below the 2K size limit enforced by many browsers or other HTTP infrastructure components, such as proxies.
The disadvantage of this solution is that you are now no longer able to create these parameters by hand because of the encoding. Therefore, Portal provides you with the above mechanism of adding a simple URI at the end of a portal URL


Reset WCM_GLOBAL_CONTEXT when switching portal pages


JSR-286 based Web Content Viewer portlet does not make use of the WCM_GLOBAL_CONTEXT query parameter but instead uses a public render parameter as defined by the portlet standard to holds its context information. By default all public render parameters are shared across pages in Portal.

So what happens is that when you select the link to the item on the first page a public render parameter is set that basically tells the JSR-286 Web Content Viewer portlet, that was configured to listen to broadcast links from other portlets, to renders the content item that was set in the public render parameter. When you then switch to the next page all public render parameter are maintained and also available on the second page. Thus the web content viewer on the second page renders the content item set in the public render parameter.

To solve this you can either:
  • Set the parameter "param.sharing.scope" on both pages to a unique value. This parameter is documented here http://publib.boulder.ibm.com/infocenter/wpdoc/v6r1/topic/com.ibm.wp.ent.doc_v6101/dev/pltcom_pubrndrprm.html and controls how public render parameter for JSR portlet are scope. To have a unique scoping simply set the value of this parameter to any arbitrary but unique value.
  • Use web content pages instead of "normal" portal pages. As for web content pages the param.sharing.scope parameter is set to a unique value automatically during page creation
Note: 
If you want reset all render state(private or public render parameter) of all JSR portlets when selecting page from navigation links(generated from theme) with use of the following
<portal-navigation:urlGeneration keepNavigationalState="false"> 

Click Here( Infocenter) to see more details on JSP tag 



URI Resolver Framework 

In the newer JSR 286 viewer, you use the URI resolver framework in WebSphere Portal to address pages and content items from external systems. The URI resolver framework is a generic resolver framework that can also be leveraged for custom URI schemes. Web Content Management defines the schema wcm: as follows:
wcm:path:LIBRARY/SITE_AREA_PATH/CONTENT [[& page=unique_name | object_id] &mapping=mapping | &current=true]

means that you provide the path to the content and then optionally provide one of the following:
  • A target page, using either the unique name of the page or its object ID.
  • A URL mapping.
  • The current page selected in the URL to use before the URI.
If you don't provide any of the above, WebSphere Portal automatically tries to find the right page. This works only if you’re using the Web Content Pages, where you map a Web Content Management site area to a portal page so that WebSphere Portal is aware of the relationship.
So, how do you get a complete URL now? You have a couple of different options:
  • Address the WebSphere Portal resolver framework directly via /wps/poc or /wps/mypoc.
  • Use any URL for WebSphere Portal that is known by the external application.
Following are some sample URLs:
  • Addressing the portal resolver framework directly:
http://host_name/wps/mypoc?urile=wcm%3Apath%3A/Web+Content/NewsUS/News1
This URL tells the portal to render the content item with the library path Web Content/NewsUS/News1. WebSphere Portal will look up the Web Content Page that is mapped to the NewsUS site area (Company News/US), redirect to that page, and set the context of that page to the content item library path.
  • http://host_name/wps/mypoc?urile=wcm%3Apath%3A/Web+Content/NewsUS/News1&mapping=/coolCars
This URL tells WebSphere Portal to render the content item the same way as the previous URL, but instead of doing the dynamic page look-up to do a redirect to the page /Products/Cars, which is mapped to the URL /coolCars

The complete syntax of these kind URL's is:
/wps/[my]poc[/vp]?urile=wcm:path:[path to WCM content][&page=[unique name or ID] | &mapping=[url mapping] | &current=true]
  • poc for un-authenticated access
  • mypoc for authenticated access
  • To address a virtual portal append the VP mapping. E.g.:
    /wps/mypoc/myvp
    /wps/poc/myvp
  • Alternatively to using the poc servlet you can also append the "urile" parameter on any Portal URL including URL that contain URL mappings e.g to address a specific portal page defined by the url mapping use /wps/[my]portal[/url mapping]?current=true&urile=wcm:path:[path to WCM content]
  • To address a specific portal page use one of the following parameters exclusively:
    • page=unique name or ID of page
    • mapping=url mapping label
    • current=true (To stay on the current page)
  • To leverage dynamic WCM page lookup: ommit any page parameter

There must be at least one JSR 286 web content viewer portlet on the target page and it must be configured to receive links from Other portlets and this portlet,

Note: You actually have two choices: you can specify "uri" or "urile." The difference is that if you use the uri scheme, you need to follow the URI encoding rules in addition the URL encoding rules, so the URL:
http://host_name/wps/portal/Company+News/NewsEurope?urile=wcm%3Apath%3A/Web+Content/NewsUS/News2&current=true

would look like this using the "uri" scheme:
http://host_name/wps/portal/Company+News/NewsEurope?uri=wcm%253Apath%253A%2FWeb%2BContent%2FNewsUS%2FNews2%26current%3Dtrue



Incompatiable javascript's encodeURIComponent() and Java's URLEncoder.encode()

There is incompatibility between the javascript encodeURIComponent and java URLEncoder.encode method.

URLEncoder.encode (Java API for URLEncoder)
When  you encode a string using the URLEncoder.encode method following rules apply

  • The alphanumeric characters "a" through "z", "A" through "Z" and "0" through "9" remain the same.
  • The special characters ".", "-", "*", and "_" remain the same.
  • The space character " " is converted into a plus sign "+".
  • All other characters are unsafe and are first converted into one or more bytes using some encoding scheme. Then each byte is represented by the 3-character string "%xy", where xy is the two-digit hexadecimal representation of the byte. The recommended encoding scheme to use is UTF-8. However, for compatibility reasons, if an encoding is not specified, then the default encoding of the platform is used.  

from the above rules, java URLEncoder.encode will treat [-a-zA-Z0-9._*-] as litterals .

JavaScript encodeURIComponent

     JavaScript's encodeURLComponenet [-a-zA-Z0-9._*~'()!] as litterals . and space will converts as "%20".

Following is implementation of javascript compatiable encoding in java

public static String encodeURIComponent(String originalStr){
    String encodeString= null;
    try{
      encodeString = URLEncoder.encode(s, "UTF-8") 
                         .replaceAll("\\+", "%20")
                         .replaceAll("\\%21", "!")
                         .replaceAll("\\%27", "'")
                         .replaceAll("\\%28", "(")
                         .replaceAll("\\%29", ")")
                         .replaceAll("\\%7E", "~");

    }catch (UnsupportedEncodingException e)    {
      System.out.println("Exception while encoding");
    }

    return encodeString;  } 


Another approach if you are using the JAVA 6, using the javascript engine that ships with JDK1.6

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public static String encodeURIComponent(String originalStr){
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        engine.eval("print(encodeURIComponent(originalStr))");
}