Traducir a :

martes, 1 de julio de 2014

¿Qué son los eventos contextuales en ADF?

En muchas ocasiones necesitamos compartir información entre fragmentos y páginas pero tenemos el inconveniente de que no hay manera que los cambios que se realicen en algún fragmento puedan ser vistos por otro fragmento o página. Para esto se pueden utilizar los eventos contextuales los cuales se basan en el concepto Productor - Consumidor, en el cuál un fragmento Productor publica un evento hacia un data control compartido "EventHandler", luego la página o fragmento Consumidor tomará los valores recibidos desde "EventHandler" realizados por el Productor.

A continuación se presentaran paso a paso con un ejemplo el paso de valores de un fragmento a otro usando eventos contextuales.

Tenemos 2 fragmentos, Consumidor.jsff y Productor.jsff, cada uno de estos con sus respectivos task flow y managed bean. El fragmento productor contiene una tabla en la cual al seleccionar una fila se debe generar el evento contextual de pasar el objeto de la fila seleccionada al fragmento consumidor. (La tabla es de tipo Persona con un String nombre y un String apellido). El fragmento Productor.jsff se presenta así:


1. Sobre la tabla debemos obtener la fila seleccionada, para esto creamos un método en el SelectionListener llamado getRowListener:



2. Para obtener la fila ejecutamos el siguiente código:

  public void getRowListener(SelectionEvent selectionEvent) {

    pSelect = (Persona)tablaBinding.getSelectedRowData();


 }

pSelect es una variable global de tipo Persona al cual le asignamos el objeto seleccionado en la tabla.

 3. Ahora en el PageDef del Productor.jsff generamos un eventBinding:




4. Ahora vamos a generar el Data Control compartido la cual guardará los cambios que haga el fragmento productor. Creamos una clase java llamada EventHandler.java con la siguiente información:

public class EventHandler {
 
  private Persona persona;
 
  public EventHandler() {
    super();
  }
 
  public void actualizarPersona(Object p){
   
    if(p != null){     
      this.persona = (Persona)p;   
    }
   
  }



5. Luego generamos un Data Control a partir de la clase EvenHandler.java:



6. Sobre en PageDef de Productor.jsff y creamos un methodAction de la función "actualizarPersona" creada en el paso 4.



6. En la configuración del methodAction seleccionamos el data control EventHandler y la operación actualizarPersona (paso 4), en la columna value seleccionamos el objeto pSelect (paso 2)


7. Creamos el evento. En la pestaña Structure clic derecho sobre el eventBinding del fragmento y seleccionamos "events":


8. Le damos un nombre al evento, en este caso "productorEvent":


9. Luego vamos de nuevo a la función getRowListener en ProductorBean.java del fragmento Productor.jsff (paso 2) y ejecutamos el methodAction "actualizarPersona" y el evento "productorEvent" (paso 8):

  public void getRowListener(SelectionEvent selectionEvent) {

    pSelect = (Persona)tablaBinding.getSelectedRowData();

    JsfUtil.executeOperation("actualizarPersona");
       try {
         // Ejecucion Evento Contextual
           JsfUtil.invokeActionListenerMethod("#{bindings.productorEvent.listener.processAction}",
                                          this.addButton);
            } catch (Exception e) {
              e.printStackTrace();
             }
    }


(Al final de este tutorial se encuentran las funciones de la clase JsfUtil).

10. Ahora vamos a programar la parte del consumidor. En el fragmento consumidor hay un inputText en donde aparecerá la fila seleccionada desde el fragmento productor.



11. Creamos una clase llamada BaseBean.java. Esta clase será extendida por todos los managed bean de la aplicación, en esta crearemos el método executeAction() sin implementación.


package util;

public class BaseBean {
  public BaseBean() {
    super();
  }
 
  public void executeAction(){
   
  }
}


12. En la clase EventHandler agregamos la siguiente función:

  public void executeFragmentAcceptAction(Object fragmentBean) throws Exception {
          
           // Validate if the Object of fragment is not null
           if (fragmentBean != null) {
               // Define a instance of BaseBean to execute executeAcceptAction
               BaseBean bean = (BaseBean)fragmentBean;
               bean.executeAction();
              
           }else{
                 System.out.println("The fragment bean is null!");
           }
       }


13. Recreamos el Data Control EventHandler (paso 5).

14. En el PageDef del fragmento agregamos los iteradores del Data Control compartido "EventHandler": EventHandlerIterator, personaIterator, y el atributo nombre que es el que mostraremos en el inputText del fragmento.



 15. Luego agregamos el methodAction "executeFragmentAcceptAction" y como parámetro ponemos el bean del consumidor.


16. Luego nos dirigimos al Structure del PageDef del fragmento consumidor, clic derecho y seleccionamos "Edit Event Map"

17. Agregamos un nuevo EventMap. Se necesitan 3 parámetros como Producer indicamos productorEvent del paso 8, como nombre del evento el mismo "productorEvent", y como Consumer el methodAction "executeFragmentAcceptAction":





18. Finalemente en el managed  bean del fragmento consumidor sobreescribimos la función executeAction del BaseBean (paso 11). El managed bean del fragmento debe extender de BaseBean.

  @Override
  public void executeAction() {
    try {

      DCIteratorBinding iterEventRoot =
        JsfUtil.getIterator("EventHandlerIterator");
      iterEventRoot.executeQuery();

      DCIteratorBinding iterPersona =
        JsfUtil.getIterator("personaIterator");
      iterPersona.executeQuery();
     
      Object obj = JsfUtil.getElObject("#{bindings.nombre.inputValue}");
     
      if(obj != null){
        this.nombreSeleccionado = obj.toString();
      }
                 
      this.personaBinding.setValue(JsfUtil.getElObject("{bindings.nombre.inputValue}").toString());
     
      AdfFacesContext.getCurrentInstance().addPartialTarget(this.personaBinding);

    } catch (Exception e) {
      e.printStackTrace();
    }

  } 



(Al final de este tutorial se encuentran las funciones de la clase JsfUtil).

19. Arrastramos los task flow de los fragmentos consumidor y productor a una página y probamos la funcionalidad:


Definición de la clase JsfUtil:

public class JsfUtil {
  public JsfUtil() {
    super();
  }

  public static Object executeOperation(String operationName) {
    return getOperationBinding(operationName).execute();
  }

  public static OperationBinding getOperationBinding(String operationName) {
    return (OperationBinding)getBindingContainer().getOperationBinding(operationName);
  }

  public static DCBindingContainer getBindingContainer() {
    return (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
  }

  public static void invokeActionListenerMethod(String expEL,
                                                UIComponent component) throws Exception {
    ActionEvent ae = new ActionEvent(component);
    resolveMethodExpression(expEL, null, new Class[] { ActionEvent.class },
                            new Object[] { ae });
  }

  public static Object resolveMethodExpression(String expEL, Class returnType,
                                               Class[] argTypes,
                                               Object[] argValues) throws Exception {

    FacesContext facesContext = getFacesContext();
    ELContext elContext = facesContext.getELContext();
    MethodExpression me = createMethodExpression(expEL, returnType, argTypes);
    Object obj = me.invoke(elContext, argValues);

    return obj;
  }

  public static FacesContext getFacesContext() {

    return FacesContext.getCurrentInstance();
  }

  public static MethodExpression createMethodExpression(String expEL,
                                                        Class returnType,
                                                        Class[] argTypes) {
    FacesContext facesContext = getFacesContext();
    Application app = facesContext.getApplication();
    ExpressionFactory elFactory = app.getExpressionFactory();
    ELContext elContext = facesContext.getELContext();
    MethodExpression methodExpression =
      elFactory.createMethodExpression(elContext, expEL, returnType, argTypes);
    return methodExpression;
  }

  public static DCIteratorBinding getIterator(String iteratorName) {
    String name =
      iteratorName.endsWith("Iterator") ? iteratorName : iteratorName +
      "Iterator";
    return getBindingContainer().findIteratorBinding(name);
  }

  public static Object getElObject(String expr) {
    FacesContext fc = FacesContext.getCurrentInstance();
    //        ValueBinding vb = fc.getApplication().createValueBinding(expr);
    //        return vb.getValue(fc);
    ExpressionFactory elFactory = fc.getApplication().getExpressionFactory();
    ELContext elContext = fc.getELContext();
    ValueExpression valueExp =
      elFactory.createValueExpression(elContext, expr, Object.class);
    return valueExp.getValue(elContext);
  }

}



Descarga de la aplicación: https://www.dropbox.com/sh/a5z3pmael5ax8km/AAA5Uj8IpBZW_Wk9ERhASmjKa


¿Quieres compartir esta publicación?