IBM WAS Liberty Profile 8.5.5.4

Liberty profile saves hours of development time  for WebSphere developers with its simplicity and configurable modules architecture. Especially when working with WebSphere Application Server where it includes so many integration components (ofcourse they are so useful at enterprise level) and it may take longer times to publish changes or to restart the server. But modularized architecture (configurable features) of liberty profile make these changes almost instantly.

Few new features introduced in the WAS Liberty profile are
  1. Java Servlets 3.1
  2. Dynamic Routing
  3. Concurrency Utilities for Java EE1.0
  4. Javascript object Notation Processing (JSONP)
  5. Java API for WebSocket 1.0
  6. Java Persistence API 2.0
  7. Application Security 1.0


  1. Install Liberty profile development tools for eclipse
    1. From eclipse go to "eclipse marketplace" , help-->eclipse market place
    2. Enter the following in search box "IBM Websphere Application Server Liberty Profile Developer Tools"
    3. Select version specific to your eclipse


  1. Select all confirm


  1. After installation ask for restart of eclipse

  1. Install Liberty profile server runtime from eclipse
    1. To install the liberty profile runtime  , Eclipse Menu --> Window Preference -->Server --> Server Runtime
    2. Click on add to add new server runtime (make sure you have selected isntall from archive option)
    1. Select download and install a new runtime environment from and provide the installation directory.
 

 
  1. And select the optional plugin if any you want to install



  1. I just chose couple of sample applications while installing (but it is not mandatory , if not selected anything it just installs liberty profile runtime )



  1. Create a server profile
    1. Once the Liberty server runtime installed , now you can add/create the server profile from the eclipse servers view. (new --> server-->select liberty server runtime-->give the name of the server profile)

                     

  1. Deploying the application on WAS Liberty profile
    1. You can deploy the applications different way just like tomcat, I mostly either drop the war/ear file in liberty profile dropins folder or add project direct from the eclipse. You can find the dropin folder in liberty installation.

C:\IBM\WAS85Liberty\usr\servers\LibertyServer\dropins

IBM Connections Playground

Worked on the IBM Connections couple of years back and when I wanted to test small changes to Connections Theme or for any API development it wasn't easy .  But recently came across the IBM connections development playground where you can just use the IBM lotus greenhouse account and play with different API call to pull data (that uses IBM greenhouse account)






It provides both javascript and java code snippets and it is great way test simple api changes


References


Short Text Element Type in WCI feed (WCM Content Integrator)

Web Content Integrator was introduced in the portal 6.1.5 and it is one of best way to import the content into the WCM from the external systems and used this tool so many times in different migrations . But wondered to see that documentation for the short text element is missing in IBM Infocenter/Lotus wiki's product documentation.

Usually you can use text element in feed alternatively like below,

<ibmwcm:element name="Headline">
<ibmwcm:type>text</ibmwcm:type>
<ibmwcm:value>New Product Released</ibmwcm:value>
</ibmwcm:element>


But in scenarios where short text element may be good fit if you are planning to store the string of 255 characters or less (255 bytes).   To use short text element in the feed use it as below

<ibmwcm:element name="userid">
<ibmwcm:type>shorttext</ibmwcm:type>
<ibmwcm:value>srvaka234adf</ibmwcm:value>
</ibmwcm:element>


Reference


  1. v8.5 http://www-01.ibm.com/support/knowledgecenter/SSHRKX_8.5.0/mp/wci/wci_ff_nse_element.dita
  2. V8.0 http://www-01.ibm.com/support/knowledgecenter/SS3JLV_8.0.0/wci/wci_ff_nse_element.dita?lang=en
  3. V7.0 http://www-10.lotus.com/ldd/portalwiki.nsf/xpDocViewer.xsp?lookupName=IBM+Web+Content+Manager+7+Product+Documentation#action=openDocument&res_title=Element_control_element_wcm7&content=pdcontent
  4. V6.1.5 : http://www-01.ibm.com/support/knowledgecenter/SSHRKX_6.1.5/com.ibm.wp.ent.doc_v615/wci/wci_ff_nse_element.html?lang=en

Displaying feeds using Digital Data Connector - Yahoo News Demo using DDC


This article demonstrates how to display news feed(yahoo) in portal without any coding required.

One of new feature introduced in the Websphere Portal and Content Management 8.5/8.0.0.1  is Digital Data Connector , where WCM authors can configure  RSS/ATOM feeds  and make style changes in the WCM itself and display them on portal.


1.       DDC is enabled by default in the WP8.5 but if you are on the 8.0.0.1 we need to enable it using the following command.
ConfigEngine.sh action-enable-plr -DwasPassword=password -DPortalAdminPwd=password

2.       By Default, out of the box  DDC plugin can read the both ATOM and RSS feeds ( But need to configure or update Resource environment provider properties). 
Note: You can write custom plugin for reading any custom source and generate beanlist.

3.       Using yahoo news feed to demonstrate DDC (Render the  yahoo news using the Web Content Viewer portlets on portal for this demo). Using yahoo news for the demo, but you can configure any rss feed in this method . (But if your feed is ATOM format you need use different set of resource environment provider properties to map the xml)


Sample Feed XML format
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
<channel>
<title>Yahoo News - Latest News & Headlines</title>
<link>http://news.yahoo.com/</link>
<description>The latest news and headlines from Yahoo! News. Get breaking news stories and in-depth coverage with videos and photos.</description>
<language>en-US</language>
<copyright>Copyright (c) 2014 Yahoo! Inc. All rights reserved</copyright>
<pubDate>Thur, 01 Jan 2015 12:46:00 -0500</pubDate>
<ttl>5</ttl>
<image>
<title>Yahoo News - Latest News & Headlines</title>
<link>http://news.yahoo.com/</link>
<url>http://l.yimg.com/rz/d/yahoo_news_en-US_s_f_p_168x21_news.png</url>
</image>                
<item>
<title>Wreckage, bodies reveal jet's fate days after it disappeared</title>
<description>
<p>
<a href="http://news.yahoo.com/wreckage-bodies-reveal-jets-fate-131429475.html">
<img
src="http://l.yimg.com/bt/api/res/1.2/b0JWI_jfaEgi.RqUmFb53Q--/YXBwaW_AP_FINANCIALTIMES/61a65017444cb333690f6a7067005a8d_original.jpg"
width="130" height="86"
alt="Wreckage, bodies reveal jet&#039;s fate days after it disappeared"
align="left"
title="Wreckage, bodies reveal jet&#039;s fate days after it disappeared"
border="0" />
</a>
Images of debris and a bloated body flash across Indonesian television screens.
</p>
<br clear="all" />
</description>
<link>http://news.yahoo.com/wreckage-bodies-reveal-jets-fate-131429475.html</link>
<pubDate>Thur, 01 Jan 2015 12:46:00 -0500</pubDate>
<source url="http://www.ap.org/">Associated Press</source>
<guid isPermaLink="false">wreckage-bodies-reveal-jets-fate-131429475</guid>
<media:content
url="http://l.yimg.com/bt/api/res/1.2/b0JWI_jfaEgi.RqLTIMES/61a65017444cb333690f6a7067005a8d_original.jpg"
type="" width="130" height="86" />
<media:text type="html">
<p>
<a href="http://news.yahoo.com/wreckage-bodies-reveal-jets-fate-131429475.html">
<img
src="http://l.yimg.com/bt/api/res/1.2/b0JWI_jfaEgiTTP_AP_FINANCIALTIMES/61a65017444cb333690f6a7067005a8d_original.jpg"
width="130" height="86"
alt="Wreckage, bodies reveal jet&#039;s fate days after it disappeared"
align="left"
title="Wreckage, bodies reveal jet&#039;s fate days after it disappeared"
border="0" />
</a>
Images of debris and a bloated body flash across Indonesian television screens.
</p>
<br clear="all" />
</media:text>
<media:credit role="publishing company" />
</item>
</channel>
</rss>


4.       Used default content library that is "Web Content" for demo
5.       Following are things need to create in WCM (not concentrating much on UI )
a.       Authoring Template with one text element


b.      Create PZN component with pluggable resources as content spot




Header markup
<div role="main">
<div id="header">
<h1>
[Plugin:ListRenderingContext action="getListProperty" key="title"]</h1>
<div id="channelImg">
<a href="
[Plugin:ListRenderingContext action="getListProperty" key="link"]">
<img name="
[Plugin:ListRenderingContext action="getListProperty" key="imageTitle"]" title="[Plugin:ListRenderingContext action="getListProperty" key="imageTitle"]" alt="[Plugin:ListRenderingContext action="getListProperty" key="imageDescription"]" src="[Plugin:ListRenderingContext action="getListProperty" key="imageUrl"]" height="[Plugin:ListRenderingContext action="getListProperty" key="imageHeight"]" width="[Plugin:ListRenderingContext action="getListProperty" key="imageWidth"]" border="0" align="top" >
</a>
</div>
<div id="channelDesc">
<p>
[Plugin:ListRenderingContext action="getListProperty" key="description"]</p>
</div>
</div> <!-- End header-->
<div id="feedsBody">
<table class="lotusTable" border="0" cellspacing="0" cellpadding="0" role="presentation">
<tbody>


Result design
<tr>
<td class="lotusLastCell">
<h4>
<a href="
[AttributeResource attributeName="link" separator=","]" target="_blank">[AttributeResource attributeName="title" separator=","]</a>
</h4>
<div class="lotusMeta">
[AttributeResource attributeName="pubDate" format="DATE_MEDIUM" separator=","]
</div>
</td>
</tr>
<tr class="lotusDetails">
<td class="lotusLastCell">
<p>
[AttributeResource attributeName="description" separator=","]</p>
</td>
</tr>

Footer markup
</tbody>
</table>
</div> <!-- End body-->
<div id="footer">
[Plugin:ListRenderingContext action="getListProperty" key="copyright"]
</div> <!-- End footer-->
</div> <!-- End main-->


c.       Presentation Template
Once presentation template is finished, set this as default in the above authoring template
Markup

[Plugin:ListRenderingContext action="set" profile="ibm.portal.rss" extension-id="ibm.portal.ddc.xml" attribute="source=[Element context='current' type='content' key='feedUrl']"]


d.      Create  SiteArea and Content using above authoring template and give the yahoo news feed url

e.       

6.       Create a page and add Web Content Viewer portlet to it and configure web content viewer portlet with above content.

7.       Add following resource environment provider custom properties need to create in WP ListRenderingProfileService
NOTE:: These Entries are actual mappings to the xml elements in feed

name="rss.Name"                                 value="ibm.portal.rss"
name="rss.NamespaceMapping.media"                 value="http://search.yahoo.com/mrss/"
name="rss.ListItemSelection"                         value="//item"
name="rss.ItemAttribute.id"                         value="./title"
name="rss.ItemAttribute.title"                         value="./title"
name="rss.ItemAttribute.description"                 value="./description"
name="rss.ItemAttribute.link"                         value="./link"
name="rss.ItemAttribute.author"                 value="./author"
name="rss.ItemAttribute.category"                 value="./category"
name="rss.ItemAttribute.comments"                 value="./comments"
name="rss.ItemAttribute.guid"                         value="./guid"
name="rss.ItemAttribute.pubDate"                 value="./pubDate"
name="rss.ItemAttribute.pubDate.Type"         value="Date"
name="rss.ItemAttribute.pubDate.Format"         value="EEE, d MMM yyyy HH:mm:ss z"
name="rss.ItemAttribute.source"                 value="./source"
name="rss.ItemAttribute.encoded"                 value="./content:encoded"
name="rss.ItemAttribute.enclosureType"         value="./enclosure/@type"
name="rss.ItemAttribute.enclosureUrl"                 value="./enclosure/@url"
name="rss.ItemAttribute.itunesDuration"         value="./itunes:duration"
name="rss.ItemAttribute.mediaContentURL"         value="./media:content/@url"
name="rss.ItemAttribute.mediaEncoded"         value="./media:encoded"
name="rss.ListProperty.title"                         value="/rss/channel/title"
name="rss.ListProperty.link"                         value="/rss/channel/link"
name="rss.ListProperty.description"                 value="/rss/channel/description"
name="rss.ListProperty.language"                 value="/rss/channel/language"
name="rss.ListProperty.copyright"                 value="/rss/channel/copyright"
name="rss.ListProperty.pubDate"                 value="/rss/channel/pubDate"
name="rss.ListProperty.pubDate.Type"                 value="Date"
name="rss.ListProperty.pubDate.Format"         value="EEE, d MMM yyyy HH:mm:ss z"
name="rss.ListProperty.ttl"                         value="/rss/channel/ttl"
name="rss.ListProperty.category"                 value="/rss/channel/category"
name="rss.ListProperty.cloud"                         value="/rss/channel/cloud"
name="rss.ListProperty.docs"                         value="/rss/channel/docs"
name="rss.ListProperty.generator"                 value="/rss/channel/generator"
name="rss.ListProperty.imageTitle"                 value="/rss/channel/image/title"
name="rss.ListProperty.imageLink"                 value="/rss/channel/image/link"
name="rss.ListProperty.imageUrl"                 value="/rss/channel/image/url"
name="rss.ListProperty.imageWidth"                 value="/rss/channel/image/width"
name="rss.ListProperty.imageHeight"                 value="/rss/channel/image/height"
name="rss.ListProperty.imageDescription"         value="/rss/channel/image/description"

8.       Add following  custom property in "WP ConfigService" (adding url  to ajax proxy for allowing the reverse proxy)
name="wp.proxy.config.urlreplacement.digital_data_connector_policy.yahoo" value="http://news.yahoo.com/*"

9.       Restart the server , once portal restarted I yahoo news feed as below on the portal .


Reference

PUMA API Scenarios (Portal User Management Architecture)

This article talks more about not so frequently discussed PUMA API related scenarios with samples


1.        Accessing the PUMA from webapp that is deployed on the portal (not part of themes or portlets)
        a.       If user doesn't have the portal security context in request 
        b.      Want to execute the PUMA as system user (where you want to access to all users)

2.        Searching for multiple users by passing the list of uid's without using the wildchars ( search using wildchar may returns thousands of results ) 
       a.       Searching the users based on the multiple attributes 
       b.      Retrieving multiple user objects using 'OR' condition like uid='user1' or uid='user2'
       c.       Retrieving users without using the wildcard chards

3.        Using Paged Search in PUMA
       a.       To handle large result sets returning from the LDAP.

Accessing the PUMA from webapp deployed on the Portal or Making the PUMA api calls without logging into portal.

     /*
      * <p>Execute as authenticated admin user(retrieve users without login to portal)</p>
      * <p> You can return the list of users instead of printing them by just uncommenting couple of statement in this method </p>
      */
     //public List<User> getUsersByLastName(final String lastName) throws Exception{
     public String printUsersByLastName(final String lastName) throws Exception{
                 
          final PumaLocator pumaLocator = pumaHome.getLocator();
          final PumaProfile pumaProfile = pumaHome.getProfile();
         
          final List<String> attribList = new ArrayList<String>();
          attribList.add("uid");
          attribList.add("cn");
          attribList.add("sn");
        
          //final List<User> usersList = new ArrayList<User>();
          final StringBuffer sb = new StringBuffer();
   PrivilegedExceptionAction<Void> privilegedAction = new PrivilegedExceptionAction<Void>() {
  
        @Override
        public Void run() {
          try{
            //search users who have the same last name i.e users with last name as "vaka"
            List<User> users = pumaLocator.findUsersByAttribute("sn", lastName);
            //usersList.addAll(users);
            for(User user : users){
            Map<String, Object> attributesMap = pumaProfile.getAttributes(user, attribList);
            for (Map.Entry<String, Object> entry : attributesMap.entrySet()) {
               sb.append(entry.getKey() + " : " + entry.getValue() +" , \t");
            }
            sb.append("\n").append("</br>");
          }
          }catch(Exception ex){
               System.err.println("Error while gettting the users from the PUMA");
          }
              return null;
          }
         };

         try {
              PumaEnvironment pumaEnv = pumaHome.getEnvironment();
              pumaEnv.runUnrestricted(privilegedAction);
         } catch (PrivilegedActionException ex) {
              System.err.println("error while executing the previleged action");
              ex.printStackTrace();
         }
        
         //return usersList;
         return sb.toString();

     }

Searching for multiple users by passing list of Uid’s (or any attribute) without using the wild chars

/*
 * <p> Execute the FindUsersByQuery with or condition(retrieve users without login to portal)</p>
 * <p> You can return the list of users instead of printing them by just uncommenting couple of statement in this method </p>
 */
 //public List<User> getListOfUsers(List<String> userIds) throws Exception{
 public String printListOfUsers(List<String> userIds) throws Exception{
        
          final PumaLocator pumaLocator = pumaHome.getLocator();
          final PumaProfile pumaProfile = pumaHome.getProfile();
         
          final List<String> attribList = new ArrayList<String>();
          attribList.add("uid");
          attribList.add("cn");
          attribList.add("sn");
        
          //final List<User> usersList = new ArrayList<User>();
          final StringBuffer usersDetailsStr = new StringBuffer();
         
          if(null == userIds || 0 == userIds.size()) return "Empty userIds List passed";
          final StringBuilder userIdsListQuery = new StringBuilder();
          int i = 0;
          if( 1 == userIds.size() ){
                userIdsListQuery.append("(uid='"+userIds.get(0)+"*')");
          } else {
               for (String uid : userIds) {
                    if(i == 0) {
                    userIdsListQuery.append("((uid='"+uid+"*') or ");
                    }else if(i == userIds.size()-1)
                    userIdsListQuery.append("(uid='"+uid+"*'))");
                    else
                    userIdsListQuery.append("(uid='"+uid+"*') or ");
                    ++i;
                }
          }
                
   PrivilegedExceptionAction<Void> privilegedAction = new PrivilegedExceptionAction<Void>() {
     @Override
     public Void run() {
       try{

        List<User> users = pumaLocator.findUsersByQuery(userIdsListQuery.toString());
        //usersList.addAll(users);
        for(User user : users){
           Map<String, Object> attributesMap = pumaProfile.getAttributes(user, attribList);
           for (Map.Entry<String, Object> entry : attributesMap.entrySet()) {
              usersDetailsStr.append(entry.getKey() + " : " + entry.getValue() +" , \t");
           }
           usersDetailsStr.append("\n").append("</br>");
        }
                
      }catch(Exception ex){
         System.err.println("Error while gettting the users from the PUMA");
      }
         return null;
     }
    };

         try {
              PumaEnvironment pumaEnv = pumaHome.getEnvironment();
              pumaEnv.runUnrestricted(privilegedAction);
         } catch (PrivilegedActionException ex) {
              System.err.println("error while executing the previleged action");
              ex.printStackTrace();
         }
        
         //return usersList;
         return usersDetailsStr.toString();
     }

Paged Search in PUMA

    /*
      * Print All users (using the paged search)
      * <p> You can return the list of users instead of printing them by just uncommenting couple of statement in this method </p>
      */
     //public List<User> getAllUsers() throws Exception{
     public String printAllUsers() throws Exception{
                
          final PumaLocator pumaLocator = pumaHome.getLocator();
          final PumaProfile pumaProfile = pumaHome.getProfile();
         
          //Page size is 5
          final Map<String, Object> configMap = new HashMap<String, Object>();
          configMap.put(PumaLocator.RESULTS_PER_PAGE, new Integer(5));
         
          final List<String> attribList = new ArrayList<String>();
          attribList.add("uid");
          attribList.add("cn");
          attribList.add("sn");
        
          //final List<User> usersList = new ArrayList<User>();
          final StringBuffer sb = new StringBuffer();
              
          PrivilegedExceptionAction<Void> privilegedAction = new PrivilegedExceptionAction<Void>() {

  @Override
  public Void run() {
  try{
   //you can use findUsersByQuery or findUsersByAttribute
   //PagingIterator<User> users=pumaLocator.findUsersByQuery("uid='*'", configMap);
   PagingIterator<User> users=pumaLocator.findUsersByAttribute("uid""*", configMap);
   List<User> temp = new ArrayList<User>();
   while(users.hasNextPage()){
      temp = users.getNextPage(temp);
      //usersList.addAll(temp);
      if(null != temp && 0 < temp.size()){
         for (User user : temp) {                                          
 Map<String, Object> attributesMap = pumaProfile.getAttributes(user, attribList);
      for (Map.Entry<String, Object> entry : attributesMap.entrySet()) {
        sb.append(entry.getKey() + " : " + entry.getValue() +" , \t");
      }
      sb.append("\n").append("</br>");
     }
    }
   }                      
                  
  }catch(Exception ex){
     System.err.println("Error while gettting the users from the PUMA");
  }
  return null;
 }
 };

         try {
              PumaEnvironment pumaEnv = pumaHome.getEnvironment();
              pumaEnv.runUnrestricted(privilegedAction);
         } catch (PrivilegedActionException ex) {
              System.err.println("error while executing the previleged action");
              ex.printStackTrace();
         }
        
         //return usersList;
         return sb.toString();