Archivo

Posts Tagged ‘ADF Faces’

ADF tips: Jugando con la validación condicional en un formulario

ADF tips

Uno de los requerimientos más típicos en una aplicación es hacer que un formulario cambie sus validaciones en función del valor introducido en uno de sus campos. Hasta la versión 12c no ha sido cuando Oracle nos ha ofrecido la forma de gestionar este tema de una forma sencilla y elegante.

En versiones anteriores la forma más típica de hacer estas comprobaciones extra era implementar un control en el submit del campo o del formulario donde hacer las validaciones y mostrar el mensaje de error en caso de que fuese necesario.

Una de las mejoras interesantes de la versión ADF 12c es el tag af:target. El caso de ejemplo es muy sencillo, dentro de un formulario tenemos un campo de texto y una lista de valores. En función del valor seleccionado en la lista de valores, el campo de texto puede ser obligatorio o no. Aquí un ejemplo del código de formulario:

<af:inputListOfValues id="lovF1" popupTitle="Search and Select: #{bindings.TipsField1.hints.label}" value="#{bindings.TipsField1.inputValue}" label="#{bindings.TipsField1.hints.label}" model="#{bindings.TipsField1.listOfValuesModel}" required="#{bindings.TipsField1.hints.mandatory}" columns="#{bindings.TipsField1.hints.displayWidth}" shortDesc="#{bindings.TipsField1.hints.tooltip}">
        <f:validator binding="#{bindings.TipsField1.validator}"/>
</af:inputListOfValues>

<af:inputText value="#{bindings.TipsField2.inputValue}" label="#{bindings.TipsField2.hints.label}" required="#{bindings.TipsField1.inputValue eq 'AP'}" maximumLength="#{bindings.TipsField2.hints.precision}" id="itF2">
        <f:validator binding="#{bindings.TipsField2.validator}"/>
</af:inputText>

El comportamiento por defecto es que una vez el campo de texto es obligatorio, el usuario no podrá cambiar el valor seleccionado en la lista de valores. Mostrando un error de validación referente al campo obligatorio.

Ahora bien, si añadimos un af:target dentro del componente de la lista de valores podremos evitar este comportamiento. Permitiendo al usuario poder cambiar de valor de la lista de valores sin tener que informar el campo de texto. Utilizando la siguiente instrucción:

<af:inputListOfValues id="lovF1" popupTitle="Search and Select: #{bindings.TipsField1.hints.label}" value="#{bindings.TipsField1.inputValue}" label="#{bindings.TipsField1.hints.label}" model="#{bindings.TipsField1.listOfValuesModel}" required="#{bindings.TipsField1.hints.mandatory}" columns="#{bindings.TipsField1.hints.displayWidth}" shortDesc="#{bindings.TipsField1.hints.tooltip}">
        <f:validator binding="#{bindings.TipsField1.validator}"/>
        <af:target execute="@this" render="itF2"/>
</af:inputListOfValues>

<af:inputText value="#{bindings.TipsField2.inputValue}" label="#{bindings.TipsField2.hints.label}" required="#{bindings.TipsField1.inputValue eq 'AP'}" maximumLength="#{bindings.TipsField2.hints.precision}" id="itF2">
        <f:validator binding="#{bindings.TipsField2.validator}"/>
</af:inputText>

Así de esta forma podremos implementar validaciones condicionales dentro de un formulario sin tener problemas con los campos dependientes. Más abajo os dejo un par de enlaces a la documentación oficial del componente y otro para que podáis probar el comportamiento del tag dentro en la ADF RichClient – Demo.

Documentación tag af:target : http://docs.oracle.com/middleware/1212/adf/ADFUI/af_ppr.htm#BABHDJBC

ADF RichClient – Demo af:targethttp://jdevadf.oracle.com/adf-richclient-demo/faces/components/target.jspx

ADF tips: Incorporar un selector de fecha a un af:inputText

ADF tips

Hace unos días un desarrollador posteó en los foros de Oracle que requería introducir el selector de fecha en un af:inputText que admitiría tanto valores de texto como fechas. En este ADF tips voy contaros la solución que aporté (link al post)

Para empezar debemos añadir un inputText y un inputDate:

00

El siguiente paso es asociar al inputText el valor que seleccionemos en el inputDate.

Para ello es necesario, poner en el inputDate la propiedad autoSubmit = true y utilizar el valueChangeListener para poder asignar el valor al inputText. También tenemos que añadir un partialTrigger al inputText para que se refresque automáticamente al seleccionar la fecha en el inputDate.

01

El valueChangeListener que utilizaremos es el siguiente.

02

También es necesario cambiar la fecha para adecuarla al formato que queramos, ya que por defecto tendríamos el siguiente formato: Tue Jul 07 00:00:00 CEST 2015

El método findComponentInRoot lo podemos encontrar en la clase JSFUtils.

Leer más…

Nueva release (11.1.1.9.0) de Oracle JDeveloper and Oracle ADF 11g

El pasado día 12/05/15 se lanzó al público la versión 11.1.1.9.0 de Oracle JDeveloper and Application Developer Framework. Se trata de una actualización de la versión anterior, la 11.1.1.7.0 (sí, se han saltado la 11.1.1.8.0), en la que se incluyen algunas de las características que están disponibles en la versión 12c.

Podemos descargarlo en este link de la web oficial de Oracle.

Se incluyen mejoras en varios apartados. En cuanto a JDeveloper IDE, actualiza la versión del WebLogic Server integrado hasta la versión 10.3.6 y también se incluye en la instalación por defecto el plugin de GIT para el control de versiones.

Donde más características nuevas hay es en los componentes visuales que nos permiten mostrar la información de una forma u otra. Se incluyen varios nuevos tipos de elementos y se incluyen mejoras en algunos ya existentes. Las principales modificaciones se centran en mejorar la respuesta al usuario, haciendo uso de HTML5 a la hora de renderizar los gráficos.

Nuevos componentes ADF  View

  • af:panelSpringBoard: Permite ofrecer una lista de opciones forma de iconos o pestañas y mostrar la información en un área inferior.

panelSpringBoard_tab

  • af:panelDrawer: Ofrece un menú lateral basado en iconos y la información se visualiza en el área principal, facilitando así la navegación.

diagram

  • af:deck: Es un nuevo contenedor que permite visualizar un carrusel de componentes, proporcionando una transición animada en cada cambio. Permite además que la transición sea manual o automatic.

deck

Actualizaciones de componentes ya existentes

  • Calendar: Se incluye la posibilidad de definir un estilo propio para días significativos, además se añade la opción de incluir el total de horas en la cabecera del día. Por último, se permite al usuario modificar el tamaño de las actividades en las visas de día y semana.
  • Export to CSV: Se añade soporte a exportación a CSV además de la exportación a excel ya existente.
  • Nuevas opciones de mostrar gráficas al usuario, como: zoom, scroll, etiquetas, ocultar o mostrar datos.

En cuanto a la capa de Business Components podemos ver que hay nuevas opciones para buscar un dato concreto sin tener que hacer uso de ViewCriterias; se trata de definir un Row Finder y hacer uso de él para buscar un dato concreto sin alterar el contenido actual del View Object. Además, se incluyen nuevos operadores para comparar fechas incluidas en un View Criteria. También se incluye alguna mejora en la integración con servicios SOAP, más concretamente en el uso de View Object polimórficos y la recuperación de etiquetas de objetos y atributos haciendo uso de un nuevo método getDfltObjAttrHints().

También hay mejoras en la integración de ADF con la máquina del cliente, se añade soporte para Windows 8 y Excel 2013. Se incluyen nuevos componentes, propiedades, acciones… que aportan nuevas opciones que ofrecer al usuario. Tal vez lo más interesante puede ser la propiedad de AllowCancel, la cual permite al usuario cancelar un ActionSet que haya ido mal o esté tardando mucho en ejecutarse.

Por último, se han incluido soluciones a defectos reportados por usuarios del framework, además de una serie de errores internos que no han sido publicados.

Podemos obtener más información sobre las novedades de la release 11.1.1.9.0 en este link a la sección de JDeveloper de web de Oracle.

ADF tips: Cómo enlazar componentes de vista a un Managed Bean

En este tip explicaremos una forma alternativa con la que acceder a componentes JSF desde un managed bean.

La forma más común es añadir un objeto UIComponent como atributo de nuestro bean, con sus accessors correspondientes y enlazar el componente en la página con este atributo. Esta es la vía que JDeveloper nos da por defecto para acceder a componentes JSF desde un bean:

binding="#{myBeanScope.MyBean.myRichcomponentName}"
UIComponent myRichComponentName;

public void setMyRichComponentName(UIComponent myRichComponentName){
   this.myRichComponentName = myRichComponentName;
}

public UIComponent getMyRichComponentName(){
   return myRichComponentName;
}

Esta opción nos puede ocasionar varios problemas. El primero de ellos es que estos objetos no son Serializables, con lo que en entornos de alta disponibilidad obtendremos errores. Otra contra es que el consumo de memoria es elevado, además de que el árbol JSF no será liberado completamente tras su uso y estos objetos perdurarán en memoria más tiempo del que realmente necesitamos.

Llegados a este punto podemos decir que la forma estándar no es del todo óptima, pero… ¿qué otras opciones tenemos?

Existe la posibilidad de utilizar Component Reference de Apache Trinidad (ver detalles de la API), mediante el cual no almacenaremos el componente JSF sino que guardaremos una referencia de acceso directo al componente del árbol JSF. Con esto el consumo de memoria bajará considerablemente y no tendremos objetos en memoria que no necesitemos. Tendríamos que sustituir el código anterior por algo similar a esto:

binding="#{myBeanScope.MyBean.myRichcomponentName}"
private ComponentReference myRichComponentName;

public UIComponent getMyRichComponentName(){
   return myRichComponentName == null ? null : myRichComponentName.getComponent();
}

public void setMyRichComponentName(UIComponent myRichComponentName) {
   myRichComponentName = ComponentReference.newUIComponentReference(myRichComponentName);
}

La parte negativa de este tip es que no podemos configurar JDeveloper para que automáticamente haga uso del componente. Pero gracias al uso de plantillas de código podemos aplicarlo sin tener que recordar las líneas exactas.

El uso de plantillas de código en JDeveloper lo comentaremos en un próximo ADF tip.

ADF tips: Convertir a archivo PDF

adf-tips

En esta ocasión explicaremos como pasar a un archivo PDF  los datos de un componente <af:table> de ADF Oracle.

Para poder realizar dicha acción hemos utilizado la librería iText. Esta librería nos ayudará a crear y manipular archivos PDF.

  • Creamos un botón, donde invocaremos la acción para obtener el componente table.

blog3_1

blog3_2

  • En nuestra clase bean crearemos un método printAction para obtener la información del componente table. Para obtener el componente table hemos utilizado el método invokeOnComponent (que vimos en nuestro anterior post ADF tips: Usando el ContextCallback).
  • Crearemos una clase que implemente la clase ContextCallback (es la que nos recoge el componente table).

blog3_4

  • Implementamos un método dentro de ella  para pasar el componente RichTable al archivo PDF.

blog3_5

  • Para introducir en la tabla las columnas hemos creado un método printerColumn donde recorremos las columnas de la tabla RichTable para conseguir sus valores e introducirlos en el componente PdfCell, donde éste será añadido a la tabla que va a ser pintada en el archivo PDF.

blog3_6

ADF tips: ¿Este View Object tiene resultados?

En este breve tip comentaremos los diferentes métodos para saber si un View Object tiene o no resultados en un determinado momento.

Existe el método ViewObjectImpl.getEstimatedRowCount() que internamente hará uso del método getQueryHitcount(), que a su vez envolverá la query del View Object bajo un select count(*) y nos devolverá un objeto de tipo long con el número de filas.

long numeroFilas = myViewObject.getEstimatedRowCount();

Otro método es el ViewObject.getRowCount(), que recorrerá todas y cada una de las filas haciendo uso del método next() para saber cuántas filas hay en ese momento. Como bien parece, el uso de este método puede ocasionar graves problemas de rendimiento en caso de que el View Object tenga un número elevado de registros.

int numeroFilas = myViewObject.getRowCount();

Si hacemos caso a los manuales oficiales, y a la mayoría de recomendaciones, el método más óptimo es getEstimatedRowCount(), pero en la práctica este método también puede ocasionarnos algún problema de rendimiento. Por ejemplo, si invocamos a este método en un View Object cuya sentencia tiene un coste muy elevado (acceso a una tabla de varios millones de registros), puede llegar a ocasionar problemas de rendimiento en nuestra aplicación.

La mayoría de veces hacemos uso de estos métodos para comprobar si hay o no resultados en un View Object, bien tras ejecutar una consulta o bien a la entrar a una pantalla por primera vez. Para evitar posibles problemas de rendimiento debemos pensar formas alternativas para comprobar si tenemos o no resultados. La forma más simple es comprobar si el método first() devuelve un resultado o no.

boolean hayUnaFila = myViewObject.first() != null;

Esta misma idea podemos aplicarla a otros escenarios, como puede ser contar si una consulta sólo nos ha devuelto 1 resultado o por el contrario ha devuelto 2 o más filas. Podemos acceder al iterador del ViewObject y, una vez posicionados en el primer elemento, el método hasNext() nos dirá si tenemos 2 resultados o simplemente 1.

RowSetIterator myIterator = myViewObject.createRowSetIterator(null);
boolean hayUnafila = myIterator.first() != null;
myIterator.next();
boolean hayAlMenosDosFilas = myIterator.hasNext();
myIterator.closeRowSetIterator();

ADF tips: Usando el ContextCallback

adf-tips

En este tip explicaremos cómo acceder a un componente de Oracle ADF sin implementar el método binding, que es aquel que nos proporciona acceso a los datos que contiene un determinado componente UIComponent. Para ello utilizaremos la interface ContextCallback.

  • Haremos un ejemplo con un botón que debe interactuar con el componente <af:table>.

blog2_1

  • Pondremos el botón en nuestra página y lo ligaremos a un método printAction en nuestro bean, que realizará el print de la tabla mediante una clase que  implementa la interface ContextCallback.

blog2_2

  • Un ejemplo del método action, donde le pasamos el id de nuestro componente a la clase ComponentContextCallBack. Lo importante en este código es la llamada al método invokeOnComponent que es el que va a buscar nuestro componente.

blog2_3

blog2_3

  • Nuestra clase, que implementa  la interface ContextCallback, es la que nos recoge el componente table y donde implementaremos toda la lógica que queramos realizar sobre nuestro componente. 

blog2_5

A partir de este punto es fácil desarrollar métodos que interactuen con los componentes sin necesidad de utilizar la propiedad binding de los componentes.