lunes, 8 de octubre de 2012

OTN WebCenter Portal: Rescatando Post de interés

Ante un problema con Oracle WebCenter existen dos lugares donde encontrar información (Oracle My Support y los foros oficiales):
  • Oracle My Support: Para todo Partner de Oracle, se puede tener acceso ayuda por parte de la propia Oracle ante problemas serios. También, es un gran repositorio en el que consultar problemas que pueden haber sido resueltos.
  • OTN WebCenter Portal: Foro oficial de WebCenter Portal donde la gente que trabajamos con el producto intentamos ayudar y compartir soluciones a problemas que se tienen con el producto.
  • OTN WebCenter Content: Foro oficial de WebCenter Content (UCM) con ayuda relativa al gestor de contenidos y Site Studio.
  • OTN JDeveloper & ADF: Para cualquier problema con el Framework base de los productos de Oracle, es el foro por excelencia.
 En este post intentaré recoger algunos de los últimos Post interesantes que rescato de mis ratos libres por OTN:
  • Ejecución en Threads de ADF BC: En este Post se comenta que para ejecutar transacciones en distintos Threads. Es necesaria la creación de una instancia del AppModule para el nuevo hilo y hacerle un release al final del hilo ejecutor. Esto se debe a que el hilo nuevo no tiene acceso al AppModule de la session.
  • Las PageTemplate parecen "desrregistrarse" de JDeveloper: Con la versión de PS3 de JDeveloper. Existía un Bug en el que parecía que las pageTemplate "desaparecían", es decir, cuando se entra en modo diseño de una página, la etiqueta <af:pageTemplate> aparecía en rojo y en la visión de estructura no cargaba bien la página completa. El error se debia a un bug con pagetemplate-metadata.xml.
  • El parámetro SortSpec en la llamada al servicio GET_SEARCH_RESULTS parece que no funciona: En muchas ocasiones se implementa accesos a UCM mediante RIDC para realizar consultas. En algunas de ellas existe la necesidad de que los resultados vengan ordenados por más de un criterio por lo que los parámetros SortField y SortOrder no vale. Existe un parámetro SortSpec que permite la adición de más campos de ordenación. Sin embargo, siguiendo la documentación oficial y la forma de poner los campos puede traer a que el servicio de errores de "parseo". En el Post se comenta la solución para OracleTextSearch y los llamados SDATA que son metadatos configurados para ordenación desde la "Configuration Manager" de UCM.
  • Dónde se almacenan las imágenes/recursos de WebCenter Portal : Spaces y su administración: Una de las dudas que suelen surgir a programadores y arquitectos es: ¿Dónde se almacenan las imágenes de Spaces?. Cuando se trabaja con WebCenter Portal : Spaces se suele trabajar con el proyecto llamado DesignWebCenterSpaces, a través del cual se suben todo tipo de recursos a nuestra aplicación WebCenter. Las imágenes se ubican bajo una carpeta llamada /oracle/webcenter/siteresources/scopeMD/shared . Al exportar los recursos de portal, existe la posibilidad de llevarse estos recursos compartidos de portal y cargarlos en WebCenter. Éstos son almacenados en el MDS configurado para esta aplicación. En este post hay bastantes consejos prácticos de tratamiento de esta carpeta.
  • Anclas/Anchors con ADF: Cómo realizar anclas con <af:goLink>.
  • $wcUrl y default-navigation-model.xml: Una de las numerosas preguntas que existen por el foro del uso de $wcUrl. Este TAG solamente busca por la "default-navigation-model" del momento, por lo que si se quiere que funcione para más navegaciones, debería de registrarse "navigation-reference" a otras navegaciones.
  • Refresco de página / tabla tras invocar en diálogo un Task Flow: Combinación de returnListener con PPR programático para el refresco de un UIComponent de la página tras volver de un Task Flow ejecutado como diálogo.
  • Cómo obtener los usuarios que pertenecen a un espacio en concreto: Post bastante interesante que hace uso de WebCenter API y del esquema de WebCenter para que un usuario X pueda consultar los usuarios que pertenecen a un espacio en concreto. La idea consiste en atacar a la tabla WC_SPACE_USR_DETAIL a través de la cual se pueden obtener los usuarios y grupos que pertenecen al espacio. Hay que tener en cuenta que si se trata de un grupo, hay que obtener de LDAP los usuarios pertenecientes a ese grupo.
  • Expandir <af:panelBox> masivamente: En este post se da una referencia a un ejemplo para conseguir colapsar/expandir panelBox anidados de un solo click. Hay que tener en cuenta que deben encolarse los eventos porque sino el funcionamiento esperado no será el correcto (solo se colapsaran de uno en uno cada click).
  • Entendiendo pageFlowScope: La pageFlowScope es local al TaskFlow.
  • Más acerca de $wcUrl y navigations model: Similar al comentado más arriba, pero con mucha más información.
  • Código JavaScript util para redirigir a una página de búsquedas con parámetros: Un ejemplo compartido y descargable con código interesante y reutilizable. El código recoge el texto de búsqueda y redirige a una página de búsqueda externa. Recomendable.
  • Skinning en WebCenter: Info acerca de Skinning en WebCenter.
  • PhaseListener vs Listener de una sola página: No solo existen los ADF Phase Listener que se ejecutan siempre sino que también pueden registrarse Listeners individuales para ciertas páginas.
  • Construyendo aplicaciones WebCenter Portal multilenguaje: Interesante post con comentarios e ideas acerca de cómo construir aplicaciones WebCenter multiidioma.
  • ADF Phase Listener: Cuántas veces ejecuta un ADF Phase Listener en una request.
  • Navegación de 4 niveles y código reusable: Ejemplo de que sí puede construirse navegaciones de N niveles.
  • Iframes en ADF: Cómo usar iframes en páginas ADF de WebCenter.
  • Iframes para mostrar recursos estáticos HTML del proyecto PortalWebAssets: El proyecto PortalWebAssets está pensado apra almacenar estáticos. La EL Expression a usar para acceder a recursos HTML de este proyecto se describe en este post. <af:inlineFrame source="#{preferenceBean.baseResourceURL}/sample.html"/>
 Hay mucha más información interesante por OTN y Oracle My Support, invito a todos que compartan sus problemas y soluciones a través de ellos.

sábado, 6 de octubre de 2012

Bug en navegación de espacios en WebCenter Portal : Spaces PS5

Recientemente el blog de A-Team ha publicado información acerca del "bug" de WebCenter Portal : Spaces por el cual las navegaciones tanto de páginas como de espacios parece no funcionar.

Enlace al post de A-TEAM

En este post os quería comentar la solución temporal a dicho "bug" hasta que no se proporcione una solución oficial.

Muchas veces las navegaciones de espacios son implementadas en puro JSTL  + HTML donde el enlace se genera mediante un:

- <af:goLink destination="/webcenter/spaces/yourSpaceName"/>
- <a href="/webcenter/spaces/yourSpaceName"/>

En navegadores como IE 7 e IE8, al cabo de una cierta navegación y por cuestiones de caché de estos navegadores, la navegación deja de funcionar sin poder acceder a los espacios.

¿Cómo solucionar este problema?
Mediante el uso de un <af:commandLink> o componente con actionListener.
La solución lo que hace es ejecutar un Manage Bean del propio API de WebCenter para registrar internamente el espacio al que se navega.

Por lo que el enlace quedaría del siguiente modo:

<af:forEach items="{spaceContext.spacesQuery.unionOf['USER_JOINED'].shape['ROOT_LEVEL'].listSpaces}"
                            var="gsNode">
<af:commandLink partialSubmit="true" immediate="true" actionListener="#{o_w_w_sc_i_v_b_communitySwitcherPopupBean.launchSpace}" text="#{WCTruncator[gsNode.displayName]['25']}" id="gil1">
                                     <f:attribute name="spaceName" value="#{gsNode.name}"/>
</af:commandLink>
</af:forEach>

¿Implicaciones de este cambio?
Los indexadores / crawlers entienden solo de enlaces, una navegación programática como la de la solución puede acarrear problemas para los buscadores.

domingo, 5 de agosto de 2012

Oracle WebCenter Portal / Spaces: Páginas corruptas en el MDS

Durante la configuración en Runtime de las páginas creadas en portales, tanto de WebCenter Portal como de WebCenter Portal : Spaces, puede ocurrir que una EL Expression mal configurada deje la página corrupta y sin posibilidad de edición.

En la versión PS5 de WebCenter, en caso de error se refresca la página perdiendo los últimos cambios realizados. Incluso puede aparecer otra ventana en la que se permite al usuario elegir entre eliminar la última "customización" o todas las realizadas.

Error de Oracle Composer en un error al editar un componente en WebCenter PS5
Sin embargo, en versiones anteriores a la PS5 se hace necesario modificar manualmente el MDS para recuperar la página.

¿Cómo se puede arreglar dicha página?.
Toda configuración realizada sobre las páginas son almacenadas en el MDS (Metadata Repository Service) y por lo tanto pueden recuperarse para ser modificadas.

Existen dos formas de recuperar la página del MDS y solucionar el problema:
- Mediante scripts WLST.
- Mediante el Task Flow de Oracle Composer, Customization Manager.

Recuperación por WLST
A nivel de WebLogic Scripting Tool, existen dos comandos principales para poder realizar los cambios pertinentes sobre el MDS:
exportMetadata(nombreAplicacion,nombreServidor,pathDestino,filtro)
importMetadata(nombreAplicacion,nombreServidor,pathFuente,filtro)


Mediante estos comandos es muy fácil exportar / importar los datos almacenados en MDS para una aplicación de WebCenter Portal y modificar los datos necesarios en la page / pageDef de la página corrupta.
Para más información leer la siguiente documentación: (sobre todo para saber que filtros aplicar o para exportar e importar únicamente los datos del MDS necesarios).
http://docs.oracle.com/cd/E28271_01/web.1111/e13813/custom_mds.htm#BEICFGAI

Recuperación por el Addon de Oracle Composer, Customization Manager.
Para poder solucionar los problemas en las páginas desde Oracle Composer, es necesario activar el Customization Manager Task Flow.

Para ello, en el archivo de configuración adf-config.xml configurar el siguiente panel
<addon-panels show-default-addons="true">
  <addon-panel name="oracle.adf.pageeditor.addonpanels.customization-manager"/>
</addon-panels>


Activar Customization Manager Task Flow (adf-config.xml)
Al redesplegar la aplicación de WebCenter Portal o Portal : Spaces. Acceder a Oracle Composer desde una página correcta. Como se puede observar existe un nuevo botón para acceder a la nueva funcionalidad.

Botón de Oracle Composer para acceder a Customization Manager
Al acceder a la funcionalidad del Customization Manager, saldrá una ventana en la que se permite la descarga de todas las "customizaciones" realizadas en la página actual. Para poder descargar / cargar las de la página corrupta únicamente se tiene que sustituir en la caja de texto la página actual por la corrupta.

Customization Manager y su funcionalidad para descargar / cargar customizaciones
Descargar la page o la pageDef según el error de configuración que se haya realizado, arreglarlo y volver a cargarlo.

viernes, 13 de julio de 2012

ADF 11g: af:query + af:table con datos precargados al iniciar

Al hacer Drag & Drop de una Named Criteria de una View (del Data Control de un Application Module), se puede crear un formulario de búsqueda con una tabla asociada para el manejo de los datos de nuestra base de datos.
Drag & Drop para formulario de búsqueda + tabla
Cuando se ejecuta la vista se puede observar que por defecto la tabla está vacía puesto que no se ha realizado ninguna búsqueda.
Tabla vacía nada más cargar la vista
Esto se debe a que es necesario que se realice una búsqueda (aunque sea con los campos vacíos) para que la tabla se rellene. Sin embargo, modificando el binding asociado a la View Criteria sobre la que se basa el af:query se puede lograr precargar una búsqueda para que cuando se cargue la página salgan datos inicialmente.
Para conseguirlo únicamente es necesario modificar el atributo InitialQueryOverriden poniendo su valor a true.
Modificación del binding a la View Criteria para precargar la búsqueda
Con esta configuración, al ejecutar por primera vez la vista que contiene la tabla asociada a un af:query vendrá precargada.

Datos precargados al ejecutar la vista

Ejemplo desarrollado en JDeveloper 11.1.1.6

lunes, 9 de julio de 2012

ADF 11g: JDBC Connection vs Data Source

Una de las dudas / problemas que surgen a la hora de desplegar aplicaciones ADF viene ligada con las conexiones a base de datos que se configuran en el Model de la aplicación.

En esta entrada voy a intentar aclarar cuál es el modo correcto para configurar las conexiones a BBDD de una aplicación ADF.

Cuando se comienza el desarrollo de una aplicación ADF con capa de negocio en base de datos. Lo primero que se hace es crear una conexión de Base de Datos desde las Application Resources.

Conexión a BBDD configurada
El siguiente paso es la creación de los ADF Business Components a partir de esa conexión a BBDD.
ADF BC generados a partir de la conexión

Como podrá observarse, también se ha generado un fichero llamado Model.jpx. Este fichero tiene, entre otras cosas, una conexión a BBDD. La conexión configurada en Model.jpx es la conexión de BBDD que utiliza la aplicación por defecto para generar los ADF Business Components. No es la utilizada por la aplicación en Runtime.

Model.jpx. Archivo donde se configura la conexión de la que se generan ADF BC

¿Entonces donde esta configurada la conexión que usará la aplicación?.
En los ApplicationModule.

El siguiente paso que se suele dar, es el de comenzar a utilizar directamente el Data Control generado en el View Controller. Por lo que el Data Control que se registra en DataBindings.cpx será algo parecido al siguiente:

DataControl usando la configuración Local por defecto del AppModule
Como se puede observar, la configuración del Data Control estará ejecutando la configuración por defecto del AppModule, en el caso del ejemplo MiEjemploAppModuleLocal que es una de las configuraciones por defecto que genera el AppModule.

Para cambiar las configuraciones de conexión a BBDD, así como el pool de conexiones inicial y demás parámetros comunes a una conexión de BBDD debemos ir al AppModule pestaña Configurations.

Configuraciones por defecto del AppModule

En esta ventana es donde se establece que configuración por defecto utilizará el Data Control asociado así como las distintas configuraciones que se quieran crear por si se quiere generar más Data Control con distinta conexión y parámetros de inicio.
En el caso del ejemplo se va a editar la configuración MiEjemploAppModuleLocal que es la que está por defecto configurada.
Editando la Configuración Local del AppModule
En las opciones se encuentran tres pestañas:
  • ApplicationModule: Aquí es donde realmente se configura la conexión a BBDD a utilizar. Ésta puede ser una conexión directa por JDBC URL o por Data Source (esta última es la recomendada).
  • Pooling and Scability: Aquí se configuran los datos típicos de inicio del pool de conexiones, timeouts etc...
  • Properties: Opciones avanzadas de la configuración del AppModule.
En la entrada de Blog nos centramos en la conexión a BBDD.
Como se puede comprobar, por defecto hay una conexión JDBC URL a la conexión de BBDD que se configuró al principio.
Es aquí donde tenemos que modificar para que en lugar de ejecutarse sobre una JDBC URL sea sobre un JDBC DataSource (que tenemos que habre creado en nuestro servidor de WebLogic y asociado al nodo manejado donde se ejecutará la aplicación).
Configuración por defecto al cambiar de JDBC URL a JDBC DataSource

Además, por cuestión de rendimiento, es conveniente eliminar el prefijo por defecto java:comp/env/... (en el ejemplo, java:comp/env/jdbc/MiConexionDS)

Modificación del nombre JNDI
Con este cambio lograremos que las aplicaciones ADF reduzcan considerablemente el tiempo que tardan en ser "Undeployed" del servidor. Por lo tanto el nombre del JNDI de WebLogic como el de la Configuración del AppModule quedaría como jdbc/MiConexionDS.

Pero esto no acaba aquí... 
Cuando empaquetamos la aplicación ADF en un EAR y se despliega en un WebLogic que no es el integrado veremos que tendremos problemas de conexión a BBDD aunque el Data Source esté generado correctamente puede que nos de un error en el que no encuentra la conexión a BBDD etc...
Esto se debe a que JDeveloper, por defecto, trae la opción de auto-generar y sincronizar el archivo weblogic-jdbc.xml al generar el EAR. 

¿Por qué ocurre esto?

Con la opción de sincronizado y auto-generado activada, la aplicación ADF va a buscar Data Sources globales generados en WebLogic. Como hemos hecho el renombrado del Data Source para ganar tiempo en cuanto a desarrollo en local tendremos problemas a la hora de desplegar en otros entornos.

Para evitar esto solamente hay que acceder a Application Properties -> Deployment.
Quitar la selección de Auto Generate and Synchronize weblogic-jdbc.xml Descriptors During Deployment.

Quitando la sincronización y autogeneración de weblogic-jdbc.xml
Referencias:

viernes, 6 de julio de 2012

Refrescar un UI Component externo a una af:region

Un caso muy común en el desarrollo con WebCenter Portal / Spaces es el de refrescar componentes de la página según acciones que se ejecuten en los Task Flow que esta incluye.


¿Cómo refrescar un UI Component según lo que haya ocurrido en un Task Flow?
Esta pregunta se responde fácilmente. Eventos Contextuales

La mayoría de Task Flows de WebCenter, como por ejemplo el de People Connections, disparan eventos según las acciones que se realicen en los mismos. Por ejemplo en People Connections las acciones de aceptar, ignorar o declinar una petición son disparadas.

En el siguiente ejemplo se va a simular esta problemática refrescando un af:outputLabel según los eventos que dispare un Task Flow.


En el ejemplo el caso es el siguiente:
UI Component que se refresca por PPR de una af:region
  • Tenemos un componente af:outputLabel cuyo valor debe ser modificado según ocurra algo en el Task Flow.
  • Tenemos una af:region con el Task Flow.
Para lograr hacer PPR en el UI Component consumiremos desde la pageDef los eventos disparados por la Task Flow. Seguir los siguientes pasos para realizar PPR en un componente consumiendo los eventos disparados:
  • Crear una clase Java para el manejo de eventos la cual será la encargada de realizar el PPR sobre el componente. En el caso del ejemplo, el método recibe un parámetro puesto que consumirá un valor emitido por los eventos. En muchas ocasiones no se suele necesitar el parámetro y directamente se hace PPR sin consumir nada.

    Clase de manejo de eventos que realiza el PPR
  • Crear un Data Control de la clase.

    Creación de Data Control del manejador de eventos
  • Acceder a la pageDef donde se encuentra nuestro UI Component y nuestra Task Flow y publicar en la Binding Layer un binding hacia el método del Data Control recién creado.

    Binding de tipo methodAction al método manejador
  • Abrir la pestaña de Contextual Events de la pageDef y en la pestaña Subscriber suscribirse a alguno de los eventos disparados asignando como método consumidor el método recientemente publicado en la Binding Layer. (También se puede hacer desde la Structure View, botón derecho a la pageDef y Edit Event Map).
    Suscripción de la pageDef al evento disparado por el Task Flow
  • Ejecutar la aplicación y al pulsar uno de los botones del Task Flow, el mensaje que se pasa por el payLoad (información transmitida del Task Flow a la página) será mostrado en la UI Component externa al mismo.
    PPR de la acción del Task Flow sobre el UI Component
Ejemplo desarrollado en JDeveloper 11.1.1.6

Enlace a descarga del ejemplo: RefreshUICompByEventApp

jueves, 5 de julio de 2012

ADF 11g: af:progressIndicator y af:statusIndicator

En muchas ocasiones se ejecutan servicios o procesos duros en los que la aplicación parece quedar "congelada". Para evitar que el usuario de la aplicación crea que nuestra aplicación "pasó a mejor vida" ADF nos proporciona dos componentes:

Enlace a la descarga del ejemplo

Interfaz del ejemplo
  • af:statusIndicator. Es el "simpático" iconito de la O de Oracle que cambia de icono a otro girando en el caso de que haya algún proceso en ejecución de la aplicación. Es posible modificar estos iconos (referencia a como hacerlo más adelante).
    Icono sin actividad 
  • af:progressIndicator. Es una barra de progreso típica que indica el estado de una operación. Siempre se puede usar cuando realmente se sabe el estado de la operación que se está realizando como, por ejemplo, insertar numerosas filas a base de datos (sabemos por que row del total vamos).
    Barra de progreso
¿Cómo usar cada una de ellas?

af:statusIndicator

Es el más sencillo puesto que solo se debe realizar Drag & Drop desde la paleta de componentes. Automáticamente, en caso de que alguna ejecución esté en curso, el componente cambiará entre dos gif's animados, uno estático y uno dinámico.

    Icono con actividad
    Icono sin actividad 
Componente de estado
Para cambiar estos iconos requiere aplicar Skinning de ADF. Referencias: 
af:progerssIndicator


Barra de progreso
Componente de progress con poll
Para usar la barra de progreso no basta únicamente con realizar Drag & Drop. Es necesario al menos:
  • Un Bean Java que extienda una clase abstracta del tipo BoundedRangeModel. Esta clase mantiene en todo momento cual es el máximo y cual es el valor actual de la barra de progreso.
  • Una operación af:poll para que se consulte el estado actual de la barra de progreso y se refresque.
  • Un método que se ejecute en el actionListener de la af:progressIndicator puesto que este evento es disparado cuando la barra de progreso llega a su fin y, por lo menos, hay que parar el af:poll.
El ejemplo
En el ejemplo adjunto a esta entrada se proporciona un ejemplo básico de barra de progreso junto al indicador de estado. En este ejemplo se lanza un hilo de ejecución y se refresca la barra de progreso mediante un poller (af:poll).

Para construir una barra de progreso como la del ejemplo (descarga disponible al final de la entrada) se deben tener en cuenta los siguientes pasos:
  • Crear una clase Java que extienda de BoundeRangeModel. En el ejemplo, además de poder acceder al máximo, y valor actual de la barra, se añade la posibilidad de consultar el porcentaje de la misma. Importante recordar que el bean que maneja la barra de progerso debe tener un scope mínimo de viewScope puesto que un scope menor haría que se perdiera el valor de progreso de la misma.
    Clase que implementa el modelo de la barra: BoundedRangeModel

  • Realizar Drag & Drop de manera conjunta de la af:progressIndicator y un af:poll configurando un PartialTrigger de la barra hacia el disparador de eventos programado (poll). Además, asociar en el value de la barra de progreso el bean que exitende de BoundedRangeModel.
  • Crear una clase Java encargada del manejo de la interfaz, de los valores iniciales de la barra de progreso, de iniciar / parar el poll y de lanzar / parar el proceso costoso.
    Clase controlador de los hilos / valores de la barra
  • Crear una clase que implemente Runnable para poder lanzar la ejecución en paralelo del proceso costoso y que tenga lectura sobre los valores actuales de la barra de progreso (por ejemplo una clase interna a la de manejo de la interfaz).
    Clase del proceso costoso que es lanzado como hilo
Más datos a tener en cuenta:
  • Para parar / iniciar un af:poll se debe cambiar su propiedad rendered y además el PartialTrigger debe ser al componente padre del mismo.
  • Tener cuidado con la clase Thread y verificar que realmente los hilos terminan su ejecución. Esto puede llevar a problemas en cuanto a consumo de JVM. Normalmente se generan los de incidencias de WebLogic inc_[numero] donde podremos consultar errores que han ocurrido en el hilo de ejecución.
Ejemplo desarrollado en JDeveloper 11.1.1.6

Enlace al ejemplo: BarraProgresoApp

Referencias:

miércoles, 4 de julio de 2012

ADF 11g: Variables de página

Una duda que suele surgir a la hora de crear la pageDef de una página es la siguiente:

Enlace a descarga del ejemplo

¿Para qué sirve el 'executable' variables?
Una de las funcionalidades que nos permite es la creación de "variables" asociadas a Data Controls (como cuando hacemos Drag & Drop de una View Object y genera el Iterator). Pero, por otro lado nos permite la generación de variables del tipo que queramos (por ejemplo java.lang.String).


Executable variables de una pageDef

¿Cómo puedo crear una variable?
En la propia pageDef lo podemos realizar desde la vista Structure o desde la propia pageDef haciendo click derecho en el propio ejecutable variables.
Seleccionar en Insert Inside Variables -> variable para crear una variable.


Creación de una variable en el executable variables (I)

Dar un nombre lógico y el tipo de datos de la variable.


Creación de una variable en el executable variables (II)

Generar un binding a dicha variable para facilitar el acceso a la misma. El binding será de tipo attributeValues.

Creación del Binding a la variable (I)
Elegir la fuente del binding, en este caso, variables y la variable recién creada.

Creación del Binding a la variable (II)
Con ello ya podemos usar la variable para almacenar o mostrar los valores que queramos:

Binding a la variable creado


  • Uso en JSPX.
    Uso del Binding en JSPX

  • Uso desde JAVA.
    Uso del Binding desde JAVA
Aprovechando el ejemplo comentar que se puede modificar la ruta donde crea automáticamente JDeveloper las pageDef. Para ello seleccionar en las propiedades de proyecto del ViewController. Navegar a ADF Model y en el apartado PageDef sub-package podemos decir el prefijo de carpetas donde se almacenarán las pageDef. Hay que tener en cuenta que este prefijo será adherido al ya configurado por defecto para la aplicación como ruta de paquetes base.

Cambio de ubicación por defecto de las pageDefs

Ejemplo desarrollado en JDeveloper 11.1.1.6

Enlace al ejemplo descargable: PageDefVarApp

martes, 3 de julio de 2012

ADF 11g: No se puede encontrar o invalida su entidad propietaria

Un error clásico cuando se hace un Create de una fila para una entidad es:

Enlace de descarga del ejemplo

"oracle.jbo.InvalidOwnerException: JBO-25030: La entidad de detalle Y con la clave de fila null no se puede encontrar o invalida su entidad propietaria."
Error al realizar una operación Create en una tabla Detalle sin su Maestro

¿A que se debe este error?
Cuando se tiene un modelo de datos en el que existen entidades "Maestro - Detalle" se hace muy común este problema.
El problema reside en la creación de filas en la entidad Detalle sin que la entidad Maestra se encuentre en la misma página.
Supongamos el siguiente modelo de datos: 

Modelo de datos, Tabla Maestro-Detalle. Dado un idioma, tienes los portales asociados


Como se puede comprobar, existe una relación de Foreign Key entre PortalesWeb e Idiomas por el campo ID del idioma. Esto lo que supone es que:
  • Tabla Idioma es la maestra.
  • Tabla PortalesWeb es el detalle.
Por lo tanto, al generar los Business Components se generará una asociación entre las entidades forzando una Composite Association entre ambas. Esto quiere decir que existirá una relación fuerte entre ambas y no permitirá el uso de la tabla detalle de manera independiente.

Asociación generada automáticamente con los ADF BC

¿Cómo solventar el problema si queremos contribuir más detalles en una página aparte de la tabla maestra?
Existen varias soluciones al problema: Eliminar la fuerte asociación entre entidades o usar realmente la entidad detalle conjuntamente con su maestra. A continuación se describen las dos soluciones.
  • Eliminar la fuerte asociación entre las entidades. Es lo más fácil, rápido, pero poco ético puesto que se pierde la relación a nivel de modelo de la aplicación. Sin embargo, suele ser común el uso de esta solución puesto que en numerosas ocasiones el atributo que actúa de Foreign Key realmente es una List Of Values de la tabla maestra logrando así restringir los valores posibles para dicho atributo.
    Para conseguir eliminar la fuerte asociación abrir la assoc entre las dos entidades Maestro-Detalle y cambiar la siguiente configuración:
    • En el modo Overview del XML, navegar a Relationship -> Behaviour.
      Assoc entre Maestro-Detalle sin modificar
    • Desactivar Composite Association y así no existirá más dicho problema.
      Desactivando la fuerte asociación entre entidades.

  • Usar la vista del AppModule procedente de la View Link. Con esta solución se está generando una fila para un valor determinado de la entidad maestra. Por lo que no se esta violando la restricción.
    DataControl del AppModule, explicando cada vista con su solución.
Ejemplo descargable: ForeignAssocApp

Desarrollado en JDeveloper 11.1.1.6 apoyado en una BBDD Oracle XE 10g.

Datos: El ejemplo demuestra el problema de intentar crear una fila de una entidad detalle sin su maestra. Podéis modificar el assoc para comprobar que realmente el problema desaparece con la primera solución.
El modelo y los datos iniciales se encuentran en los script: script1.sql, insert.sql respectivamente
Existe una Offline DataBase en el proyecto Model para que podais cargar automáticamente el modelo de datos en un esquema de vuestra BBDD.

Referencias:

lunes, 7 de mayo de 2012

ADF 11g: Paso de parámetros entre llamadas a Task Flows

Es muy común dividir los Task Flows en más Task Flows para facilitar el mantenimiento de los mismos. Esto hace que en numerosas ocasiones sea necesario pasar parámetros entre el Task Flow que actúa de Llamador y el Task Flow que actúa de Llamado.

Enlace a descarga del Ejemplo: EjemploParamTaskFlows.

Por ello traigo un ejemplo sencillo y explicativo de como se realiza el paso de parámetros entre Task Flows.

Para comenzar, tenemos 2 Task Flows:

  • El Llamador: Es una Bounded Task Flow basada en fragmentos que contiene una única vista encargada de realizar la llamada a otro Task Flow. Está basada en fragmentos dado que lo incrustaremos en una página de prueba llamada startApplication.jspx.
    Task Flow Llamador
  • El Llamado: Es una Bounded Task Flow basada en páginas puesto que será ejecutada por el Llamador en modo "diálog / inline-popup". Contendrá una lógica inicial basada en el parámetro consumido de entrada que decidirá a qué página de la Task Flow se va a navegar.
    Task Flow Llamado
Dado el escenario principal, estos son los pasos importantes a la hora de pasar parámetros entre Task Flows:
  • En la definición del Task Flow Llamado se debe configurar un parámetro de entrada requerido. Por ello, en la configuración propia del Task Flow en la zona de configuración de Parameters registrar un nuevo parámetro con los siguientes valores:
    Registro del parámetro de entrada del Task Flow Llamado
    • Name: Es el nombre del parámetro. En el caso del ejemplo "accion".
    • Class: Es la clase Java que define el tipo del parámetro. En el caso del ejemplo String.
    • Value: Es donde será almacenado el valor. En este caso en la pageFlowScope en una variable llamada accion.
    • Required: Marca la obligatoriedad del parámetro. En caso de ser requerido, al realizar una Task-Flow-Call nos obligará a dar un valor a dicho parámetro.
  • En el propio Task Flow Llamado existe la implementación de una lógica en base al parámetro recibido apoyada en un af:router para decidir sobre la navegación a usar. 
    Configuración de af:router de entrada basado en el parámetro de entrada
  • En el Task Flow Llamador se tiene la Task Flow Call del Task Flow. Al añadir este Task Flow Call se solicitará el parámetro configurado en el Llamado. Por ello configuraremos que dicho parámetro recoja el valor de la pageFlowScope del Llamador de una variable llamada "valor pulsado". También recordar que, como se va a realizar la llamada en modo "dialog / inline-popup", hay que configurar esto mismo en la llamada.
    Configuración de la llamada al Task Flow Llamado (Task Flow Call)
  • Únicamente faltaría cargar el dato en la variable de la pageFlowScope llamada botonPulsado. Para ello se utilizará una Operation de ADF. Concretamente af:setActionListener. Para que, cuando se pulse uno de los botones de la vista, se cargue el valor correspondiente en la variable.
    Configuración de un Set Action Listener arrastrado al botón de "editar"
      Action Listener's configurados para todos los botones. Cargando la variable botonPulsado
  • También recordar que en los botones es imprescindible establecer el atributo useWindow = true dado que estamos ejecutando la llamada en modo "dialog / inline-popup".
  • Finalmente adherir el Task Flow llamador a una página de prueba y ejecutar.
    Task Flow Llamado, pulsar en Añadir
      Ejecución en diálogo al dar al botón añadir.
Ejemplo desarrollado con JDeveloper 11.1.1.4