Integrating WebCenter Likes / Comments API - I

Integrating WebCenter Likes / Comments in Content Presenter - I

This post will explain how to use the API in order to use the Likes Service in a Content Presenter Task Flow.

"Comments part will be soon in Integrating WebCenter Likes / Comments in Content Presenter-II"

There is an OOTB Likes service implemented in WebCenter Portal allowing the users to “like” and comment the activities and content in WebCenter Portal.

Download LikesComments JDeveloper Project

For example:

Document Manager Task Flow allows to “Like“/“Unlike” Content.

 

Document Explorer - Likes
Document Explorer - Likes

 

How can I add the same functionality to the Content Presenter Templates?

The sample brings an API to retrieve the Likes / Comments information from a given oracle.webcenter.content.integration.Node (the var of the Content Presenter template).

 

package custom.oracle.webcenter.likescomments;




import java.util.HashMap;
import java.util.List;
import java.util.Map;




import oracle.adf.share.logging.ADFLogger;




import oracle.webcenter.activitystreaming.ActivityException;
import oracle.webcenter.activitystreaming.ActivityObject;
import oracle.webcenter.activitystreaming.ActivityStreamingService;
import oracle.webcenter.activitystreaming.ActivityStreamingServiceFactory;
import oracle.webcenter.comments.Comment;
import oracle.webcenter.comments.CommentsSummary;
import oracle.webcenter.content.integration.Node;
import oracle.webcenter.content.integration.RepositoryException;
import oracle.webcenter.content.integration.spi.ucm.UCMConstants;
import oracle.webcenter.doclib.internal.model.VCRUtils;
import oracle.webcenter.framework.service.Scope;
import oracle.webcenter.framework.service.ServiceContext;
import oracle.webcenter.framework.service.ServiceObjectType;
import oracle.webcenter.likes.Like;
import oracle.webcenter.likes.LikesSummary;




/**
 * Utility class to access to Likes and Comments of a specific Node.
 * This class will access in Map EL Expression way
 * TODO: Implement a Declarative Component / or bean bigger scope to don't recalculate everything
 * @author Daniel Merchan Garcia
 * @version 1.0
 */
public final class LikesCommentsProcessor {
    
    /**
     * Logger
     */
    private static final ADFLogger LOG =
        ADFLogger.createADFLogger(LikesCommentsProcessor.class);
    
    /**
     * Class name to be used by the logger
     */
    private static final String CLASS_NAME =
        LikesCommentsProcessor.class.getName();




    /**
     * Map holding nodeLikesComments
     */
    private Map<Node, NodeLikeComments> nodeLikesComments;




    /**
     * Default Constructor
     */
    public LikesCommentsProcessor() {
        super();
        
        // Implementation via Map EL expression
        nodeLikesComments = new HashMap<Node, NodeLikeComments>() {
                @Override
                public NodeLikeComments get(Object key) {
                    if (key != null && key instanceof Node) {
                        Node node = (Node)key;
                        NodeLikeComments nlc = this.getCommentsLikes(node);
                        return nlc;
                    } else {
                        return super.get(key);
                    }
                }




                /**
                 * Extract from a Node all Comments and Likes
                 * @param node
                 */
                private NodeLikeComments getCommentsLikes(Node node) {
                    LOG.entering(CLASS_NAME, "getCommentsLikes");
                    // FIXME prevent Folder item asking about isFolder
                    NodeLikeComments nlc = new NodeLikeComments();
                    nlc.setNode(node);
                    try {
                        ActivityStreamingService as = ActivityStreamingServiceFactory.getInstance().getActivityStreamingService();
                        // Extract inforamtion required for ActivityStreaming API and Likes Tag
                        String resourceId = getResourceId(node);
                        String serviceId = VCRUtils.getStringProperty(node, UCMConstants.SERVICE_ID_PROP_DEF_NAME);
                        String resourceType = VCRUtils.getStringProperty(node, UCMConstants.RESOURCE_TYPE_PROP_DEF_NAME);
                        String name = node.getName();
                        ServiceObjectType serviceObjType = as.findObjectType(serviceId, resourceType);
                        ActivityObject activityObject = as.createObject(resourceId, serviceObjType, name);
                        activityObject.setServiceID(serviceId);
                        ActivityObject actObj = ActivityStreamingServiceFactory.getInstance().getActivityStreamingService().getObjectDetailsManager().getObjectDetail(activityObject);
                        // Extract all information using ActivityObject and node information
                        if (actObj != null) {
                            nlc = getCommentsLikesFromActivityObject(actObj, nlc);
                        } else {
                            // In case of not being registered yet the Id and the Type must to be provided
                            // FIXME: Current GUID or default GUID???? to be decided...
                            nlc.setScopeGUID(ServiceContext.getContext().getScope().getGUID());
                            //nlc.setScopeGUID(ServiceContext.getContext().getDefaultScope().getGUID());
                            nlc.setActivityId(activityObject.getId());
                            nlc.setActivityType(activityObject.getType().getName());
                        }
                    } catch (RepositoryException e) {
                        e.printStackTrace();
                    } catch (ActivityException e) {
                        e.printStackTrace();
                    }
                    return nlc;
                }




                /**
                 * Auxiliar method to get the resourceId expected from the content
                 * @param node
                 * @return [repositoryName]#dDocName:[dDocNameValue]
                 */
                private String getResourceId(Node node) {
                    String repository = node.getId().getRepositoryName();
                    String dDocName = node.getId().getUid();
                    return repository   "#dDocName:"   dDocName;
                }




                /**
                 * Extract and store likes and comments from an ActivityObject
                 * @param actObj with all content information about comments and Likes
                 * @param nlc NodeLikeComments to fill
                 */
                private NodeLikeComments getCommentsLikesFromActivityObject(ActivityObject actObj,
                                                                            NodeLikeComments nlc) {
                    int commentsCount = 0;
                    int likesCount = 0;
                    Like myLike = null;
                    List<Comment> recentComments = null;
                    try {
                        // Retrieving all comments 
                        CommentsSummary commentsSummary = actObj.getCommentsSummary();
                        if (commentsSummary != null) {
                            commentsCount = commentsSummary.getCount();
                            recentComments = commentsSummary.getRecentComments();
                            for (Comment o : recentComments) {
                                // TODO: Testing API purpose
                                LOG.fine("Comment:"   o.toString());
//                                LOG.fine("AuthorId:"   o.getId());
//                                LOG.fine("CommentText:"   o.getCommentText());
//                                LOG.fine("Creation Date:"   o.getCreationDate());
                            }
                        }
                        LikesSummary likesSummary = actObj.getLikesSummary();
                        if (likesSummary != null) {
                            likesCount = likesSummary.getCount();
                            myLike = likesSummary.getMyLike();
                        }
                        nlc.setActivityType(actObj.getType().getName());
                        nlc.setActivityId(actObj.getId());
                        Scope scope = actObj.getScope();
                        if (scope != null) {
                            nlc.setScopeGUID(scope.getGUID());
                        } else {
                            nlc.setScopeGUID(ServiceContext.getContext().getDefaultScope().getGUID());
                        }
                        // nlc.setScopeGUID(actObj.getScope().getGUID());
                        //nlc.setScopeGUID(ServiceContext.getContext().getScope().getGUID());
                        nlc.setRecentComments(recentComments);
                        nlc.setCommentsCount(Integer.valueOf(commentsCount));
                        nlc.setLikesCount(Integer.valueOf(likesCount));
                        nlc.setMyLike(myLike);
                        if (LOG.isFinest()) {
                            LOG.finest(CLASS_NAME,"getCommentsLikes",nlc.toString());
                        }
                    } catch (ActivityException e) {
                        LOG.warning(CLASS_NAME,"getCommentsLikes","Error using Activity Stream API for Likes / Comments",e);
                    }
                    LOG.exiting(CLASS_NAME, "getCommentsLikes");
                    return nlc;
                }
            };
    }




    /**
     * Get map containing the nodes and likes associated to the content
     * @return Map
     */
    public Map<Node, NodeLikeComments> getNodeLikesComments() {
        return nodeLikesComments;
    }
}

 

The API is implemented in EL Expression / Map way in order to pass the Node as parameter.

#{backingBeanScope.likesComments.nodeLikesComments[node].likesCount}

With the API the following parameters are retrieved for the required input parameters of <likes:likesLink> :

Parameter Description Type
Id Id of the UI Component String
rendered Flag to render or not the component. Boolean
serviceId ID of the service that holds the content (oracle.webcenter.content, oracle.webcenter.doclib…) String
objectType Type of the content. In case of oracle.webcenter.doclib service then can be webContent, content, blog, wiki, folder String
objectId Id of the object. In case of content of oracle.webcenter.content/doclib then is [repoName]#dDocName:[dDocNameValue] String
scopeId Scope GUID of the content in case of being in a WebCenter Portal (Spaces) String
likesCount Number of likes Int
myLike Likes Services associated to the current user oracle.webcenter.likes.Like

 

The sample Content Presenter is the following:

<?xml version='1.0' encoding='UTF-8'?>  
  <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"          
            xmlns:dt="http://xmlns.oracle.com/webcenter/content/templates"          
            xmlns:af="http://xmlns.oracle.com/adf/faces/rich"          
            xmlns:likes="http://xmlns.oracle.com/webcenter/likes">    
        <dt:contentTemplateDef var="node">        
              <af:panelGroupLayout id="pgl1" layout="vertical">            
                        <!-- General information of the test node -->            
                        <af:outputText value="#{node.propertyMap['webcenter:serviceid'].value.stringValue}"                            
  id="ot1"/>            
                        <af:outputText value="#{node.propertyMap['webcenter:resourcetype'].value.stringValue}"                            
                          id="ot2"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].activityId}"                            
                          id="ot3"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].activityType}"                            
                          id="ot4"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].scopeGUID}"                            
                          id="ot5"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].commentsCount}"                            
                          id="ot6"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].likesCount}"                            
                          id="ot7"/>            
                        <af:outputText value="#{backingBeanScope.likesComments.nodeLikesComments[node].myLike}"                            
                          id="ot8"/>            
                        <!-- Likes testing -->            
                        <likes:likesLink id="ol1" rendered="#{true}"
                                                       serviceId="#{node.propertyMap['webcenter:serviceid'].value.stringValue}"                              
                            objectType="#{node.propertyMap['webcenter:resourcetype'].value.stringValue}"                              
                            objectId="#{backingBeanScope.likesComments.nodeLikesComments[node].activityId}"                              
                            scopeId="#{backingBeanScope.likesComments.nodeLikesComments[node].scopeGUID}"                              
                            likesCount="#{backingBeanScope.likesComments.nodeLikesComments[node].likesCount}"                              
                            myLike="#{backingBeanScope.likesComments.nodeLikesComments[node].myLike}"/>                  
       
              </af:panelGroupLayout>    
    </dt:contentTemplateDef>  
  </jsp:root>

It uses a scoped managed bean (registered customizing Content Presenter) using the LikesCommentsProcessor to retrieve all the information required by likes:likesLink tag.

Now the Likes button appears and works perfectly for the associated content:

 

Content Presenter with Likes
Content Presenter with Likes

 

Content Presenter with Likes / Popup
Content Presenter with Likes / Popup

 

How to deploy and use it?

The sample is deployed as shared-lib and registered in the weblogic.xml of the WebCenter Portal or Framework Portal application.

Content Presenter was customized to add the manage bean as low scope (backing or request scope).

Download LikesComments JDeveloper Project

 

Whitepaper. Migration to WebCenter Sites