martes, 15 de abril de 2014

Integrando WebCenter Likes / Comments API - I

Este post es un ejemplo de como usar el API de Activity Streaming para manejar los Likes y Comentarios de los servicios / contenidos de WebCenter Portal.


Enlace a la versión en inglés
 

Lista de gente que ha hecho Like a una actividad

"La parte de los comentarios será ampliada en Integrando WebCenter Likes / Comments API-II" (Pronto)

Hay un servicio por defecto que permite aplicar la funcionalidad de Likes sobre contenidos.

Descargar LikesCommentsExtension JDeveloper Project

Por ejemplo:
Document Manager Task Flow permite la funcionalidad de “Like“/“Unlike” sobre los contenidos almacenados en WebCenter Content.

Document Explorer trae por defecto Like

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

Este ejemplo hace uso de Activity Streaming API aplicado sobre un contenido mostrado por Content Presenter. Para ello, obtiene toda la información necesaria del contenido a partir de la variable  oracle.webcenter.content.integration.Node presente en las plantillas de Content Presenter.

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 reusable
 * @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 nodeLikesComments;

    /**
     * Default Constructor
     */
    public LikesCommentsProcessor() {
        super();
        
        // Implementation via Map EL expression
        nodeLikesComments = new HashMap() {
                @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
                    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);
                        // If the activity object is null it means that never was commented or liked
                        if (actObj != null) {
                            // Extract all information using ActivityObject and node information
                            nlc = getCommentsLikesFromActivityObject(actObj, nlc);
                        }
                    } 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 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 getNodeLikesComments() {
        return nodeLikesComments;
    }
}


El API esta implementando de tal forma que se pueda acceder en modo Map / EL Expression.

Los parámetros requeridos por el TAG que implementa Likes (<likes:likesLink>) son:

ParámetroDescripciónTipo
idIdentificador del componenteString
renderedFlag que indica si el componente debe ser renderizadoBoolean
serviceIdIdentificador de servicio de WebCenter (Por ejemplo: oracle.webcenter.content, oracle.webcenter.doclib… para contenidos)String
objectTypeTipo de contenido. En caso de ser contenido de WebCenter Content puede ser: webContent, content, blog, wiki, folderString
objectIdIdentificador del objeto de la actividad. Por ejemplo para oracle.webcenter.content/doclib es [repoName]#dDocName:[dDocNameValue]String
scopeIdIdentificador del Portal / Espacio propietario el contenidoString
likesCountNúmero actual de LikesInt
myLikeLikes Services asociado con el usuario actualoracle.webcenter.likes.Like

La plantilla de ejemplo usada con Content Presenter es la siguiente.


    
        
            
            
            
            
            
            
            
            
            
            
            
         
        
    



Como se puede observar, se usa un Managed Bean que ha sido declarado customizando Content Presenter para usar el API implementado en LikesCommentsProcessor.

Al hacer Click en el botón de Like, éste funcionara de igual manera que el que puede aparecer en el Task Flow de Document Explorer.

Botón Like en Content Presenter

Además, el popup que muestra la información de usuarios que han hecho Like funciona perfectamente.

Popup con la gente que hizo Like

Cómo usarlo?

El proyecto despliega una librería compartida que debe ser registrada en el fichero de configuración weblogic.xml de WebCenter Portal / Framework Portal.

Además, (no incluído). Se ha customizado el Task Flow de Content Presenter para añadir un Managed Bean para invocar al API.

La plantilla de Content Presenter de la imagen es la misma que la del código mostrado.

jueves, 10 de abril de 2014

CTRL + Shift + C: Acceso al modo contribución por Java

La manera estándar de acceder al modo contribución es mediante la combinación CTRL + Shift + C.

Modo contribución
Sin embargo, puede que se requiera poder realizar lo mismo mediante otra combinación de teclas o simplemente desde un botón.

Para ello no hay más que usar el siguiente fragmento de código.

import oracle.adfinternal.view.page.editor.bean.PageEditorPanelBean;
import oracle.adfinternal.view.page.editor.utils.Utility;


 if (ModeContext.getCurrent().isInEditMode()) {
    return;
 }

PageEditorPanelBean pgEditorPanelBean = PageEditorPanelBean.getCurrentInstance();

pgEditorPanelBean.toggleCCView();

Utility.refreshPageCustomizable(); 

JDeveloper advertirá que oracle.adfinternal solamente es para uso interno y que estas clases no deberían usarse. Sin embargo, no hay ninguna clase para realizar esto en el API Público como lo hay para cambiar a modo edición (Composer: CTRL + Shift + E). Por ello esta advertencia puede ser "omitida".

Advertencia de uso interno clases

La manera más rápida de probarlo es crear un Managed Bean y asociar al actionListener una acción que ejecute el código.

Cambiar a modo contribución

jueves, 27 de marzo de 2014

Extender WebCenter Portal Analytics

Recientemente he publicado un artículo técnico de cómo extender WebCenter Analytics para recolectar eventos producidos en Content Presenter.

Enlace a la página del artículo (en inglés)

Enlace directo al PDF.
Enlace directo al código.

http://goo.gl/izfpUL

En este artículo se describe lo siguiente:
  • Modelo de datos usado por WebCenter Analytics.
  • Cómo se registra un nuevo evento.
  • Cómo utilizar el API para recolectar información de los nuevos eventos.
  • Extender Content Presenter para añadir los eventos
    • Contenido visto en una plantilla de detalle.
    • Contenido visto en una plantilla de listado.
Espero que sirva para entender y conocer mejor el API de WebCenter.