Traducir a :

miércoles, 6 de agosto de 2014

¿Cómo utilizar el Task Flow Return en ADF?

El presente tutorial fue realizado para mostrar como utilizar el componente Task Flow Return para navegar entre diferentes task flows.

Vamos a crear 2 task flow: tfFragmento1.xml y tfFragmento2.xml cada uno con sus respectivos fragmentos fragmento1.jsff y fragmento2.jsff.

En el fragmento1.jsff colocamos un botón que nos dirija al fragmento 2 como se muestra a continuación:


Nos dirigimos al task flow del fragmento 1. Arrastramos un Task Flow Return y le damos un nombre y id:


Luego colocamos un Control Flow Case de la siguiente manera:



Ahora creamos un task flow principal "tfPrincipal.xml" en el que arrastraremos los dos task flow creados anteriores en el cual crearemos el flujo en donde tfFragmento1.xml se dirija al tfFragmento2.xml de la siguiente manera:



Cuando creamos un flujo desde el tfFragmento1.xml al tfFragmento2.xml en tfPrincipal.xml, en el Property Inspector de este flujo, en From Outcome aparecerá el Task Flow Return que creamos en tfFragmento1.xml como está señalado en la imagen anterior.

Ahora vamos a crear la acción para pasar de tfFragmento1 a tfFragmento2. Sobre el botón creado en fragmento1.jsff en Property Inspector - Action seleccionamos el id del Task Flow Return creado que nos aparecerá como opción:



Finalmente creamos una página y arrastramos tfPrincipal.xml, y veremos que al oprimir el botón "IR A FRAGMENTO 2" nos llevará al fragmento 2.

¿Quieres compartir esta publicación?

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?

miércoles, 9 de octubre de 2013

¿Cómo utilizar el File Adapter en un proceso BPEL?

Este tutorial fue realizado en jDeveloper 11.1.1.7.0 y su objetivo es explicar el uso de los File Adapter en un proceso BPEL.

En los procesos BPEL existen varias opciones para usar los File Adapter:

1. Read File: Se utiliza como entrada a un proceso BPEL en la cuál se realizará la lectura de archivos cada cierto tiempo especificado, llamado polling.
2. Write File: Utilizado para escribir en un archivo plano.
3. Synchronous Read File: Utilizado para realizar lecturas de archivos en medio de un proceso BPEL. (En este caso no se realiza polling).


Caso 1: Read File y Write File

En este caso se leerá el archivo plano: Persona.txt para crear un esquema Persona.xsd , y escribirlo en un archivo plano utilizando Write File en un proceso BPEL.

Para comenzar creamos una nueva aplicación BPM  incluyendo un proceso BPEL en el composite:


Luego damos las siguientes especificaciones a nuestro proceso BPEL:
- Versión: BPEL 2.0 Specification
- Template: "Define Servece Later"


Después arrastramos un File Adapter desde el Component Palette, le damos un nombre, dejamos la opción *Define from operation and schema (specified later) y escogemos la opción Read File.

Luego damos la ruta en donde se encuentran los archivos que serán leídos. Además podemos guardar en otra carpeta los archivos que van siendo leídos como vemos a continuación:


En el siguiente paso damos el nombre del archivo (o archivos) que será leído, en este caso solo darémos el nombre de archivo plano Persona.txt:



Ahora viene la opción de seleccionar cada cuanto se realizará la lectura de archivos o polling:


Ahora vamos a crear el esquema xsd a partir del archivo plano Persona.txt de la siguiente manera. Seleccionamos el ícono que dice "Define schema for native format" y se abrirá el wizard en el cual se especificarán las siguientes opciones:


En este caso nuestro archivo plano contiene varios registros de un solo tipo "Persona", por esto seleccionamos las siguientes opciones.


Después especificamos el nombre del elemento que representa nuestros registros.


Finalmente damos el nombre a nuestro esquema correspondiente al archivo plano leído, en este caso Persona.xsd



Luego de la configuración del Read File  lo unimos al proceso BPEL en el composite. En este proceso podemos definir si este proceso lo deseamos síncrono o asíncrono. Luego agregamos otro File Adapter de tipo Write. El composite quedará de la siguiente manera:


La configuración del Write File es similar.  Al momento de definir el esquema (Step 6 of 7) podemos especificar el esquema Persona.xsd creado anteriormente.

Luego abrimos el proceso BPEL. En éste arrastramos desde el Component Palette/BPEL Constructs/Web Service un "Receive" y un "Invoke":


Luego unimos Receive_ReadFile_Persona  a  ReadFile_Persona. En este momento saldrá la opción para crear la variable de entrada a este receive basados en el ReadFile, como se muestra a continuación:



Hacemos el mismo procedimiento uniendo "Invoke_WriteFile_Persona" a "WriteFile_Persona" y creamos la variable correspondiente.

Nota: Las especificaciones de los File Adapter se pueden modificar en el .jca generado por cada uno.

Después arrastramos una transformación desde Component Palette/Oracle Extensions en medio de los dos web services creados anteriormente y creamos la siguiente transformación:






Finalmente probamos nuestro proceso BPEL.

Caso 2: Synchronous Read File

En este caso se leerán 2 archivos planos: Persona.txt y Telefonos.txt. para crear un esquema con un arreglo de personas y cada uno de estos tenga una lista de telefonos. El proceso BPEL devolverá el xml de este esquema  dados los archivos planos leídos.

El archivo plano Telefonos tiene un id y un teléfono por cada línea. El id representa el id de la Persona.




Inicialmente tenemos en nuestro Business Catalog el objeto Persona:




Arrastramos un proceso BPEL al composite y damos la siguiente especificación:

Versión: BPEL 2.0 Specification
Template: Synchronous BPEL Process
Output: (http://xmlns.oracle.com/bpm/bpmobject/Data/ArrayPersona)ArrayPersona
 (ArrayPersona es un arreglo de BO_Persona)

Nota: Las anteriores especificaciones también se pueden modificar en el archivo wsdl que genera el BPEL.


Como vemos anteriormente, la salida de este proceso BPEL síncrono será  ArrayPersona, que es el objeto que llenaremos con la lectura de los archivos Persona.txt y telefonos.txt

Ahora en el proceso BPEL arrastramos un File Adapter en el cuál se leerá el archivo plano Persona.txt. Éste será de tipo "Synchronous Read File". La configuración de este File Adapter es similar al Read File pero no tendrá polling.


Luego de crear el Synchronous Read File para Persona.txt lo haremos igualmente para Telefonos.txt. Nuestro BPEL se verá de la siguiente manera:


Al momento de crear las variables de para los Invoke es importante definir las variable input y output para cada uno.

Después de esto hacemos la transformación  para crear ArrayPersona con los datos de los archivos planos de la siguiente manera:




Finalmente nuestro proceso BPEL se verá de la siguiente manera:

¿Quieres compartir esta publicación?

miércoles, 31 de julio de 2013

¿Cómo insertar un registro a una tabla de la base de datos desde un popUp en Oracle ADF?

Este tutorial fue realizado en jDeveloper 11.1.1.7.0 y su objetivo es insertar un registro a una tabla de la base de datos ingresando los datos del nuevo registro en un popUp.

Para este tutorial tenemos la siguiente tabla de Observaciones y  botón "Agregar Observación" en el fragmento "Fragmento.jsff".


Tenemos un popUp que contiene un Dialog y necesitamos agregar un nuevo registro en la tabla de la base de datos. Es necesario arrastar desde los Data Controls el View Object referente a la tabla de la base de datos que estamos trabajando, en este caso es "ObservacionesView1".



Vamos a popUp -> Propety Inspector -> Common -> PopUpFetchListener creamos la función "editPopUpListener", y en popUp -> Propety Inspector -> Common-> PopUpCanceledListener creamos la función "editPopUpCancelListener", en el Manage Bean del fragmento: "FragmentoBean.java".

Además cambiamos la propiedad de Common-> ContentDelivery a lazyUncached.


Luego nos dirigimos hacia la pestaña Bindings de la página y añadimos 3 bindings de tipo "action": "CreateInsert" , "Commit" y "Rollback". Como vemos todas estas acciones hacen referencia al Iterador: "ObservacionView1Iterator" del View Object "ObservacionView1" que estamos trabajando.



Para ejecutar un "action" desde el ManageBean de la página o fragmento podemos utilizar la siguiente función:
    public Object executeAction(String actionName) {
            BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry();
            OperationBinding operation = bindings.getOperationBinding(actionName);
            return operation.execute(); }

Luego implementamos los métodos "editPopUpListener"  y "editPopUpCancelListener":

   public void editPopUpFetchListener(PopupFetchEvent popupFetchEvent) {
        executeAction("CreateInsert");   }

  public void editPopUpCalcelListener(PopupCanceledEvent popupCanceledEvent) {
    executeAction("Rollback"); }

Ahora vamos nos dirigimos hacia las propiedades del  Dialog que se encuentra dentro del popUp y añadimos un método en Dialog-> Property Inspector -> Behavior -> DialogListener


En la función OKDialog que acabamos de crear, implementamos lo siguiente:

  public void OKDialog(DialogEvent dialogEvent) { 
    Outcome outcome = dialogEvent.getOutcome();
            if (outcome == Outcome.ok){
              executeAction("Commit");}
          else if (outcome == Outcome.no){
               executeAction("Rollback");}}
¿Quieres compartir esta publicación?