lunes, 21 de abril de 2014

Usando Resource Action Handler Tag

Una de las taglibs mas usadas por el Framework de WebCenter Portal es la del Resource Action Handler (<rah:resourceActionBehavior>

RAH Tag

Enlace versión inglés.

Descarga de la aplicación de ejemplo

Este tag permite la creación de enlaces y navegar a los detalles de los recursos/servicios definidos en WebCenter (oracle.webcenter.doclib, oracle.webcenter.page...)
Estos servicios estan definidos en el archivo de configuración service-definition.xml (ya sea dentro de una ADF JAR Lib como la mayoría de servicios OOTB o dentro de la propia aplicación de Portal). Durante la configuración de un nuevo servicio, éste suele enlazarse a un Task Flow como resource-viewer (detalle del recurso) o a una clase URL Rewriter que generara una URL con parámetros hacia la página donde se encuentra el recurso.

Uno de los ejemplos más comunes de uso de esta taglib es el fragmento de resultados del servicio de búsqueda. Cada link de cada elemento de resultado usa rah:resourceActionBehavior para enlazar con el detalle del recurso.


 
 
 

Otro ejemplo de uso de este tag puede encontrarse en los ejemplos de plantillas de Content Presenter que trae la instalación de JDeveloper (articles.jsff)


   
   
   
   
   
   
   
   
   
   


En este caso el tag enlaza con un recurso de tipo oracle.webcenter.content.presenter.
En el archivo service-definition.xml dentro de la libraría de Documentation Library View puede encontrarse que el Resource-Viewer de este servicio es precisamente el Task Flow de Content Presenter.
Para enviar parámetros diferentes a los de por defecto(resourceId, resourceType...) entonces el tag f:attribute debe ser usado conjuntamente con rah:resourceActionBehavior para poder enviar los valores que el Task Flow espera

En el ejemplo adjunto a este post puede encontrarse un sencillo ejemplo de una Framework Portal Application que define un nuevo servicio y utiliza este tag para acceder al resource-viewer asociado al mismo. Los pasos seguidos han sido:
  • Modificar service-definition.xml file definiendo un nuevo servicio denominado oracle.webcenter.merchan.sample y registrando una Custom Bounded Task Flow como resource-viewer


    
    
    Sample resource
    Sample resource for the blog
    
    


  • La Bounded Task Flow usada como Resource Viewer contiene alguno de los parámetros por defecto enviados automáticamente y uno custom para ser mostrados en un fragmento de detalle.

    Parámetros de entrada del Resource-Viewer del ejemplo
  • home.jspx modificado incluyendo rah:resourceActionBehavior tag para linkar con el nuevo servicio


  
  
  


  • Al ejecutar el ejemplo hacer Click sobre el enlace generado por el Tag y comprobar que la información fue enviada de manera correcta a la Bounded Task Flow.
Enlace generado con RAH Tag

Resource-Viewer tras hacer click al Link generado con RAH Tag

Referencias:

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