Tuesday 31 January 2012

Curso ADF 11g - Parte 3

Tema : Personalización de Componentes Entidad.

Si ha culminado con éxito las 2 primeras partes del curso, probablemente se estará  preguntando en que momento se programará. Bien tal como se ha visto en las primeras lecciones prácticamente hemos usado el asistente para generar los componentes. Esos pasos fueron vitales, porque nos brinda el esqueleto de lo que será nuestra aplicación.  Lo que toca ahora, es personalizar los componentes.

Este paso, no sólo implicará programar, sino principalmente tratar de apoyarnos al máximo en las funcionalidades  del framework para  solucionar funcionalidades recurrentes con configuraciones sencillas.  En este post cubriremos las personalizaciones de los componentes Entidad. Posteriores post, mostrarán personalizaciones sobre los View Objects y los módulos de aplicación.

Requerimiento:

  • Oracle Jdeveloper 11g. 11.1.1.3
  • Oracle Database Express 11g
  • Haber culminado la parte 2 del tutorial. Ir al capitulo 2.

Capítulos Anteriores

Parte 1: Creación del Modelo de Datos.

Parte 2: Creación de Componentes de Negocio

Opcional : 

Si no culmino los capítulos anteriores y quiere empezar desde este capítulo, puede descargar el siguiente código para continuar el curso.

 Código previo.

 

Generalmente en los proyectos que desarrollo hay requerimientos comunes que generalmente lo soluciono con la herramienta. Estos son :

  • Inicializar los valores de los identificadores únicos. (Primary Key de las tablas). Es decir, inicializar con un correlativo este campo. Para eso, usaremos un objeto sequencial en la base de datos que es la mejor práctica en estos casos.
  • Inicializar campos de fecha. Existen muchas veces campos fecha, en nuestros desarrollos, que los usuarios nos piden que se inicialice, por ejemplo, con la fecha actual. Bueno existe una manera sencilla de hacer esto que lo explicamos en este post.
  • Validaciones.  Nuestra aplicación maneja Movimientos y Detalles. Eso implica que un movimiento podría tener algún detalle. Se imagina un movimiento sin detalle?. Eso implicaría información inconsistente y obviamente debemos evitarlo en nuestra aplicación. Bueno también veamos como hacer esa validación con la herramienta.
  • Nuestra entidad Movimiento (Padre), tiene un atributo total, que debería acumular los subtotal de todos sus detalles. En este post mostraremos como programar esta regla.

Bien vemos como  implementar fácilmente estas reglas.

INICIALIZAR CORRELATIVO

1. Como comentamos al inicio, una de las actividades más comunes en el desarrollo de una aplicación, es inicializar los datos correlativos que están asociados generalmente a la PK de una tabla. En esta caso, la mejor práctica es hacer uso de un objeto sequence de la base de datos, que no asegurará usar un único valor para estos atributos. Bien empecemos creando los objetos sequence en nuestra BD.

Ejecutemos los siguientes comandos en la BD (conectado con el usuarios ventas):

create sequence cliente_seq start with 100;

create sequence producto_seq start with 100;

create sequence movimiento_seq start with 100;

 

image

2. Ahora en la bd crear triggers que actualice la pk de la tabla Cliente;


create or replace trigger insert_cliente_id
  BEFORE INSERT ON cliente
  FOR EACH ROW
DECLARE
    new_id number;
  BEGIN
    SELECT cliente_seq.NextVal
     INTO new_id from Dual;
    :new.cliente_id := new_id;
  END;

 

image

Por favor repita lo mismo para crear los triggers asociados a la tabla Producto y Movimiento

 

3. Bien, regresemos a la aplicación ADF y haga doble clic sobre la entidad Cliente.

imagen1

4. En la parte izquierda se mostrará una pantalla con la configuración asociada a la entidad Cliente. Note que la sección Attributes muestra los atributos de los clientes. Si hacemos doble clic sobre el atributo ClienteId se abrirá otra pantalla que permitirá configurar las propiedades de ese atributo.

image

Existen muchos indicadores en esta pantalla, parece una consola de avión, pero con un poco de calma podemos entender las más  importantes.

Region Attribute.

Type: No es necesario hacer una explicación larga sobre esto, sin embargo es importante destacar que el asistente define el tipo de dato adecuado según el tipo de BD  de la columna asociada.

Value Type y Value: Algunas veces queremos inicializar un atributo con un valor especifico ó en base a una formula. Bien estos campos justamente ayudan a eso. El “Value Type” determina el tipo de inicialización que usaremos, si es “Literal”, esperará un valor fijo en el campo “Value”, por el contrario si seteamos el valor a “Expression”, se esperará una formula (Se puede usar groovy) para asignar un valor.

Persisten: Indica que el atributo es persistente contra la BD, es decir hay una columna que almacenará los valores de ese atributo. La sección inferior “Database Column”, brinda la configuración asociada a esta propiedad.

Mandatory: Significa Obligatorio.

Region Updatable

Acá se determina si se permitirá laa actualización de este campo. Los valores Always y Never son evidentes en su uso. En el caso de While New indicará que ese atributo sólo se actulizará cuando ingresemos un nuevo registro. Es decir no permite actualizarse.

Region Refresh After

Algunas veces los valores de los atributos, se cargarán posteriormente a una acción de la BD. En esa región se indica después de que operación se volverá a actualizar este valor.

 

5. Bien, luego de la explicación teórica, apliquemos lo aprendido. Para asociar el atributo ClienteId con el resultado del triger de BD simplemente cambiemos su propiedad Type por DBSequence. Pulse Apply.

image

Analicemos que ha cambiado con esta configuración.

 

Region Atributte.

Se han desabilitado los campos Persitent  y PrimaryKey. Obviamente al ser campos asociados a un correlativo de BD ambas propiedades se asumen como requeridas para este cambio.

El campo mandatory se ha “ des seleccionado”, porque se hace esto?, bueno se asume que el valor de este atributo provendrá de la BD posterior a la inserción. Es decir el usuario no colocará ningún valor durante el ingreso de datos y en consecuencia la aplicación no debe validar si este campo esta vacío ó requerido.

Region Updatable

La herramienta ha colocado esta propiedad en “While New”, tiene sentido?. Pues si, porque este campo será sólo completado durante la inserción. Es decir no debe ser modificable. Es como si dejáramos modificar una Pk de base de datos.

Region Refresh After.

Se seleccionó Insert. Esto significa que el valor de atributo se actualizará posterior al ingreso de datos. Cuando vamos a crear un nuevo cliente, lo que va a pasar es que vamos a crear una instancia de la entidad, como un objeto, bien esa instancia mediante alguna acción volcará su contenido contra la tabla cliente, despues de insertarse entonces el valor del campo CLIENTE_ID de la tabla será regresado al objeto para actualizar el atributo cliente id de la instancia de la entidad. (Refresh After Insert).

 

Pulse Ok para regresar al editor.

 

6. Para probar este funcionamiento, ejecute el módulo de aplicación. Clic derecho sobre él y RUN.

image

 

7. Elija la Vista ClienteVO y pulse el boton (+)

image

 

8. Complete los datos. Note que el campo ClienteId se ha cargado con un valor temporal (-2) en este ejemplo. Es decir, no es necesario llenarlo.

Pulse el boton Commit image

image

 

9. Notará que una vez que se grabo el registro se cargó el verdadero valor del atributo ClienteId, lo que demuestra que nuestra configuración ha sido correcta.

image

 

Por favor, repita los pasos, desde el punto 3 para inicializar los atributos ProductoId de la entidad Producto y MovimientoId de la entidad Movimiento.  Cuando termine de realizar estos ejercicios puede continuar con el siguientes instrucciones del curso. No continúe si no terminar los ejercicios por que pasos posteriores requerirán que se haya culminado estos ejercicios.

 

ASIGNAR FECHA

10. Nuestra siguiente actividad, consiste en inicializar el atributo Fecha de la entidad movimiento con la fecha actual.

Bien, esta actividad es sencilla. Haga dobhe clic sobre la entidad Movimiento.

 

image

 

11. A continuación, seleccione la categoría Attributes y haga doble clic sobre el atributo Fecha.

image

 

12. La pantalla que se muestra permite configurar las propiedades del atributo Fecha. Tal como se explicó en el paso 4, podemos usar las propiedades “Value Type” y “Value” para definir los valores iniciales que tendrá las instancias de la entidad. En este caso usaremos Groovy, que es un lenguaje de Scripting, y que ADF puede usar para elaborar expresiones que se evalúan en tiempo de ejecución. Puede conocer más del uso de Groovy en ADF en el siguiente enlace.

http://radio-weblogs.com/0118231/2007/05/22.html

13. Entonces, los pasos que haremos será elegir “Expression” en la propiedad  Value Type y en el campo Valor colocará adf.currentDate. Pulse Ok.

image

 

14. Realicé el paso 6, para probar los componentes. Elija ahora la vista MovimientoVO.

image

 

15. Pulse el botón image para agregar un nuevo registro y note que se ha inicializado el campo Fecha con el valor actual.

image

 

VALIDAR MOVIMIENTO

16. En este escenario, lo que tenemos que lograr es evitar data inconsistente entre el movimiento y el detalle. La regla es que debemos evitar que un movimiento se grabe sin detalles. Esta última regla,determina una relación de dependencia entre ambas entidades que se logra por medio de una relación de composición.  Vamos a personalizar a la entidad la relación de Movimiento-Detalle a una de tipo composición. Haga doble clic sobre la Relación DetalleMovimientoFkAssoc

image

17. En el editor, elija la categoría “Relationship” y en la sección Beahivior seleccion la casilla “Composition Association”

image

 

El colocar una relación como composición brinda muchos beneficios, por ejemplo  si se realiza una transacción en la que estén involucradas las entidades movimiento y detalle, primero persistirá los datos del movimiento(padre) y luego de los hijos. Otra ventaja es que abre la posibilidad de utilizar validaciones que involucren ambas entidades. Justamente en esta caso aprovecharemos de esta configuración para validar que los movimientos tengan por lo menos un detalle.

 

18. Ahora haga clic sobre la entidad Movimiento, seleccione la categoría  “Business Rules”. En esta pantalla se puede colocar validaciones de manera declarativa sobre cualquier entidad. Las validaciones declarativas pueden aplicarse a nivel de atributo y entidad. Por ejemplo podría validar que el precio de un producto sea mayor a 0 ó aplicar un expresión con groovy para realizar esta validación.

Si quiere conocer más de este tipo de validaciones puede ir al siguiente enlace.

http://docs.oracle.com/cd/E15586_01/web.1111/b31974/bcvalidation.htm

 

Bien en esta caso hagamos clic  derecho sobre la sección “Entity Validators” y elija la opción New Validators.

 

image

 

19. La siguiente pantalla permite definir la validación que queremos aplicar sobre la entidad.  Las validaciones están compuestas de tres tabs que tienen la siguiente finalidad.

El primero “Rule Definition”, permite definir que regla determina que el dato procesado es Valido.

El segundo “Validation Execution ” determina alguna condición  para aplicar esa regla de validacíon.

El tercero “Failure Handling” ayuda a personalizar el mensaje que queremos lanzar al usuario cuando la validación no ha sido cumplida.

 

Los cambios para la primera pestaña, será : el tipo de regla será Collection y la operación que usaremos será “Count”. Además, el Operator será Greater Than, el  campor Compare With “Literal Value” y el valor colocado en el Literal Value será 0.

Que significa todo esto?. Que se hará una validación del operador count de la relación, es decir del conteo de los detalles. Luego, se espera que el valor obtenido “Sea Mayor que” un valor literal que ingresemos. En este caso 0.

image

 

20. Ahora elija la pestaña “Failure Handling” y coloque el mensaje que se disparará cuando no se cumpla la validación.

 

image

 

21. Pulse Ok, grabe los cambios y ejecutemos el modulo de aplicación, como en el paso 6, para probar este cambio. Haga clic sobre el View Link MovimientoDetalleVL, para ver la un movimiento con sus detalles.

image

22. Ahora para ver el efecto de validación. Pulse el botón image a nivel del movimiento.

 

image

23. El movimiento no tiene detalles, así que  pulsemos el botón Commit para intentar Grabar la transacción. Note que aparecerá el mensaje que se definió previamente y de esta manera se realizó correctamente la validación.

image

 

CALCULO DE UN ATRIBUTO TOTAL EN BASE A DETALLES.

24. Toca ahora realizar el calculo del atributo “Total” de la entidad Movimiento (Padre), en base a la sumatoria de los atributos “Subtotal” de la entidad Detalle (Hijo).  Esta regla es lógica, pues se supone que si usted maneja una factura que puede incluir muchos detalles de venta, esperaría que la sumatoria de todos los detalles (subtotales) se consoliden en un atributo asociado a la entidad Padre (Movimiento), llamada Total.

Si bien existe una relación entre ambas entidades aún será necesario colocar instrucciones que permitan actualizar el campo Total del Padre. Bien en este caso si requeriremos programar, y para eso necesitamos una clase que permita colocar esas reglas. Sin embargo, como habrá notado prácticamente no hemos tenido acceso a clase java alguna que nos permita hacer esa programación. Eso se debe a que el framework por default utiliza descriptores “inicialmente”  asociados a los componentes construidos. Eso lo puede usted comprobar expandiendo el componente Movimiento, por ejemplo, y descubriendo que tiene asociado un archivo XML que justamente representa dicho componente.

image

 

25. Bueno, en nuestra situación necesitaremos programa el componente Movimiento, así que habilitaremos un clase Java asociada a dicho componente. Para eso haga doble clic sobre dicho componente, elija la categoría Java y haga clic sobre la opción “Edit java options”

 

image

 

26. Bien , esta consola ofrece la opción de asociar una clase java a la entidad y personalizar su comportamiento vía código. Seleccione la opción “Generate Entity Object Class” y también la casilla de Accesors.

 

image

 

27. Note que ahora la entidad Movimiento ya no tiene asociado sólo un xml, sino que ahora hay una clase java (MovimientoImpl.java)  asociada que usaremos para modificar su comportamiento. La clase también tiene los métodos geters y setters de la entidad, por lo que podríamos hacer operaciones sobre estos métodos.

 

image

 

28. Haga doble clic sobre la clase MovimientoImpl.java y agreguemos el siguiente método.

 

public void calcularTotal(){

  float totalDetalle=0;
  RowIterator iteDetalle = this.getDetalle();
 
  while(iteDetalle.hasNext())
  {
      Row filaDetalle = iteDetalle.next();
      totalDetalle = totalDetalle + ((Number)filaDetalle.getAttribute("Subtotal")).floatValue(); 
  }
 
  this.setTotal(new Number(totalDetalle));

}

 

Analicemos el código que hemos colocado. Esté método se encuentra en la entidad movimiento y lo que hace es :

Recorrer todos los detalles asociados y  acumular sus subtotales en la variable totalDetalle

float totalDetalle=0;
RowIterator iteDetalle = this.getDetalle();
while(iteDetalle.hasNext())
{
Row filaDetalle = iteDetalle.next();
totalDetalle = totalDetalle + ((Number)filaDetalle.getAttribute("Subtotal")).floatValue();
}

 

Finalmente asignamos el valor calculado en el atributo Total de la entidad Movimiento.

this.setTotal(new Number(totalDetalle));

 

29. Este método permite actualizar el atributo Total del Movimiento. Sin embargo,  esté método no se ejecutará automáticamente, será necesario ubicar alguna acción que provoque este método. Si analizamos bien, esté cálculo se debe realizar cuando se agrega, modifica o elimina un detalle. Veamos como provocamos esto.

Haga doble clic sobre la entidad Detalle, de manera similar al paso 25, para habilitar la creación de clases. Tal como se muestra a continuación.

image

 

Revisemos que significa cada uno de sus checks.

  • Generate Entity Object Class: Esto permite asociar una clase Java a la entidad.

Sobre esta clase se crearán los métodos que se indican a continuación.

  • Accesors: Crea los métodos get y set de cada atributo. Habilítalo.
  • Data Manipulations Method: Crea el método doDML(). Este es un método muy útil que se invoca cada vez que se realiza una operación de INSERT,UPDATE ó DELETE contra la Base de datos.  Justamente en la implementación de este método colocaremos la invocación al método de calculoTotal().Habilítalo

Nota adicional: Nosotros ejecutamos este método cuando pulsamos el botón de guardar cambios en la base de datos (image) desde el módulo de aplicaciones.

  • Create Method. Crea el método Create(), que es un metodo que se dispara cuando se instancia un nuevo registro de la entidad. Es similar a un constructor de la entidad. No lo habilite.

Nota adicional: Nosotros ejecutamos este método cuando pulsamos el botón de Adicionar un nueva Fila (image) desde el módulo de aplicaciones.

  • Remore Method. Crea el método remove() que como su nombre indica cuando se elimina una instancia de la entidad. No lo habilite

Nota adicional: Nosotros ejecutamos este método cuando pulsamos el botón de Eliminar una Fila (image) desde el módulo de aplicaciones.

Pulse Ok y Grabe los cambios.

 

30. Bien, haga doble clic sobre la clase DetalleImpl.java y ubíquese en el método doDML(). Sobre escríbalo de la siguiente manera.

 

protected void doDML(int operation, TransactionEvent e) {
    this.getMovimiento().calcularTotah();
    super.doDML(operation, e);
  
}

 

31. Notemos lo siguiente, el método doDML se ejecuta cada vez que el usuario confirma una acción de agregar modificar o eliminar sobre la entidad detalle. Nosotros hemos incluido la siguiente línea

this.getMovimiento().calcularTotal();

Que lo que hace es calcular los detalles del movimiento asociado y actualizar el atributo total del mismo.

 

image

32. Probemos este último cambio. Ejecute el modulo de aplicación y ubíquese en el viewlink que permite ver los datos del movimiento y detalle,

image

 

33. Agregué un nuevo detalle usando el botón de Agregar Fila sobre los detalles

 

image

 

34. Ingrese valores pertinentes a ese detalle.

 

image

 

35. Finalmente, aplique los cambios de toda la transacción.

 

image

 

36. Finalmente notemos que el valor del total del movimiento se ha actualizado correctamente.

image

 

37. Felicitaciones, ha culminado la personalización de las entidades en su aplicación ADF. Capítulos posteriores permitirán personalizar las vistas y el módulo de aplicación. Si quiere comparar su resultado, con nuestro código puede descargarlo del siguiente enlace.

CODIGO FUENTE.

Monday 30 January 2012

Paso de Valores entre páginas ADF




Uno de las funcionalidades requeridas en una aplicación WEB es el paso de valores entre las páginas ADF. Existen 2 maneras de realizar esta actividad que vamos a analizar en este post.




1. Uso de expresiones para declarar y usar las variables. Esta es la solución más rápida pero como explicaremos mas adelante la menos recomendable. Veamos un ejemplo rápido.




En la pagina origen creamos una caja de texto en su propiedad value definimos indicamos la variable a nivel de flujo donde se almacenará lo contenido en la caja de texto.




La expresión será así :




#{pageFlowScope.parametro}




Note que la pageFlowScope determina el alcance de la variable y parametro es el nombre de la variable.




image




En la página destino usamos la misma expresión para recuperar su valor. En este caso uso un componente del tipo label para mostrar el valor.




image




Probemos la pagina y veamos que efectivamente se pasa el valor de una página a otra.




image







Al ir a la siguiente página se recupera el valor.




image




Bien aparentemente la solución propuesta es suficiente para solucionar el paso de valores entre páginas, sin embargo hay un inconveniente en esta propuesta. Si por algún motivo la aplicación sufre un error inesperado, por ejemplo una excepción de null pointer, los valores se pierden y si el comportamiento de la aplicación dependía de los valores de estas variables entonces su aplicación empezará a comportarse de manera impredecible.




Entonces, como solucionamos estos?. Bueno existe una segunda manera de lograr el paso de valores, en este caso se utiliza un managed bean para compartir la información. La ventaja de esta técnica es que los valores se mantienen aún cuando se produzca un error no controlado en la aplicación.




Para implementarlo, primero vamos a crear un bean “PasoValor” con un sólo atributo llamado parámetro. Algo como esto.







package parbizu.valores.view;







public class PasoValor {
private String parametro;
public PasoValor() {
super();
}




public void setParametro(String parametro) {
this.parametro = parametro;
}




public String getParametro() {
return parametro;
}
}







Lo declaramos en el adfc-config.xml.




image







Lo aplicamos en nuestras páginas origen y destino solo que la expresión para acceder será.




#{pageFlowScope.pasoValor.parametro}




Note que en este caso, se incluye la referencia al managed bean pasoValor en la expresión.




El código quedaría así en la página origen.




image







En la página de destino terminaría así.




image







Si probamos esto, tendríamos lo siguiente.




image







image







Recomendamos hacer uso de esta segunda técnica para evitar la perdida de valores.




CODIGO EJEMPLO