Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Java. Mostrar todas las entradas

jueves, 25 de mayo de 2017

Válvulas - File Adapter

Uso de válvulas en el File Adapter

Existe una funcionalidad de pre-procesamiento de archivos que podemos añadir al File Adapter de la Oracle SOA Suite. Personalmente no la conocía, pero me parece muy práctica y es por eso que decidí compartir esta entrada del blog.

El requerimiento es simple. Tal vez sea común trabajar con archivos de tipo CSV, posicionales, de texto plano, etc. En lo primero que pensamos para resolver una situación donde se involucren archivos es en el File Adapter.

Entre sus características están leer el archivo haciendo uso de streaming, utilizar un NXSD para transformar el contenido de manera nativa a XML, o simplemente no leer el contenido y transportar el archivo hacia algún sitio (file system, FTP).

En esta ocasión, la necesidad es un tanto "fuera de lo común": procesar un archivo de Excel.

Si bien el File Adapter no tiene entre sus capacidades nativas procesar un archivo de este tipo (me refiero a leer el contenido), tampoco es ciencia saber cómo resolver el problema. No existe una forma de transformar un archivo Excel mediante un NXSD.

Una de las opciones que puede pasar por nuestra cabeza es leer el archivo con el File Adapter (sin procesar el contenido) y posteriormente con una actividad Java Embedding procesar el contenido. Sin duda esta es una forma de abordar la solución.

Sin embargo, existe una manera más elegante de resolverlo: las válvulas y pipelines que se pueden crear para el File Adapter.

Flujo del File Adapter


El flujo que normalmente sigue el File Adapter para procesar un archivo de entrada, es el siguiente:

File System > (1) > File o FTP Adapter > (2) > Transformación (NXSD) > (3) > Proceso BPEL o Pipeline de OSB o Mediador

Donde:

(1) - El File Adapter lee el archivo o archivos de la ruta indicada
(2) - El contenido del archivo se traslada a un proceso de traducción donde mediante un NXSD transformamos el contenido a XML. El traductor publica el contenido hacia el SCA (tiempo de ejecución).
(3) - Finalmente, el SCA publica el contenido hacia el engine de servicio (BPEL, OSB, Mediator).

Flujo del File Adapter haciendo uso de Pipelines y Válvulas


En el caso de las válvulas y los pipelines, va a existir un paso intermedio, justo entre los pasos (1) y (2), el resto del flujo es el mismo.

De tal suerte que nuestro flujo de procesamiento quedaría como sigue:


File System >  (1) > File o FTP Adapter > (1A) > Pipeline > (1B) > Válvula > (1C) > File o FTP Adapter (2) > Transformación (NXSD) > (3) > Proceso BPEL o Pipeline de OSB o Mediador

Donde:

(1A) - El File Adapter va a trasladar el contenido hacia un Pipeline, que tiene asociadas válvulas de pre-procesamiento.
(1B) - El Pipeline va a ejecutar las válvulas de pre-procesamiento en el orden que nosotros indiquemos.
(1C) - La última válvula que se ejecute, va a devolver el control al Pipeline, y este a su vez va a devolver el contenido del archivo pre-procesado al FTP Adapter. A partir de ahí, el flujo es el mismo.

Implementación de la válvula


Implementar la válvula es relativamente simple. Vamos a necesitar dos proyectos: uno Java y un compuesto.

Proyecto Java


El proyecto Java contendrá básicamente el código fuente para la conversión de XLS a CSV. Para esto usamos, como dije antes, Apache POI.

La clase implementada es la siguiente:

package excelvalves;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import java.text.DateFormat;
import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Iterator;

import oracle.tip.pc.services.pipeline.AbstractValve;
import oracle.tip.pc.services.pipeline.InputStreamContext;
import oracle.tip.pc.services.pipeline.PipelineException;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public class ExcelToCsv extends AbstractValve {

    public InputStreamContext execute(InputStreamContext inputStreamContext) throws IOException, PipelineException {
        System.out.println("The valve will begin executing the inputstream");
        // Get the input stream that is passed to the Valve
        InputStream originalInputStream = inputStreamContext.getInputStream();
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        
        // Read workbook into HSSFWorkbook
        Workbook workbook = new HSSFWorkbook(originalInputStream);

        // Read worksheet into HSSFSheet
        Sheet datatypeSheet = workbook.getSheetAt(0);

        // To iterate over the rows
        Iterator<Row> iterator = datatypeSheet.iterator();

        //store the csv string
        StringBuffer data = new StringBuffer();
        
        int i = 0;

        //Loop through rows.
        while (iterator.hasNext()) {
            int j = 0;
            Row currentRow = iterator.next();
            Iterator<Cell> cellIterator = currentRow.iterator();
            while (cellIterator.hasNext()) {
                Cell currentCell = cellIterator.next();
                if (currentCell.toString().length() > 0 && i > 0) {
                    switch (currentCell.getCellType()) {
                    case Cell.CELL_TYPE_BOOLEAN:
                        data.append(currentCell.getBooleanCellValue() + ",");
                        break;

                    case Cell.CELL_TYPE_NUMERIC:
                        DateFormat df = new SimpleDateFormat("yyyyMMdd");
                        Date date = currentCell.getDateCellValue();
                        data.append(df.format(date) + ",");
                        break;

                    case Cell.CELL_TYPE_STRING:
                        data.append(currentCell.getStringCellValue() + ",");
                        break;

                    case Cell.CELL_TYPE_BLANK:
                        data.append("" + ",");
                        break;

                    default:
                        data.append(currentCell + ",");
                    }
                    if (j == 15) {
                        data.append('\n');
                    }
                }
                j++;
            }
            i++;
        }
        System.out.println("snippet from stream: " + data.toString());
        ByteArrayInputStream bin = new ByteArrayInputStream(data.toString().getBytes());
        inputStreamContext.setInputStream(bin);
        System.out.println("done processing the stream in the valve");
        return inputStreamContext;
    }

    @Override
    public void finalize(InputStreamContext inputStreamContext) {
        // TODO Implement this method
    }

    @Override
    public void cleanup() throws PipelineException, IOException {
        // TODO Implement this method


    }
}

Las librerías necesarias para el proyecto son las siguientes:


Lo siguiente es compilar, generar un perfil de despliegue y desplegar el proyecto en un JAR.


Proyecto SOA (compuesto)


Vamos a crear un compuesto con un File Adapter como servicio expuesto. En el asistente de configuración colocar lo siguiente:

Definir la interfaz posteriormente.


Mantener JNDI por default.


Seleccionar operación de lectura (no leer el contenido del archivo).


Leer cualquier archivo (*.*).


Frecuencia de lectura: 10 segundos.


Seleccionar el NXSD con el que convertiremos el CSV a XML.


Finalizar la configuración.


Una vez que tenemos el adaptador listo, vamos a crear el Pipeline. Para esto basta con crear un archivo XML nuevo (ExcelPipeline.xml), debajo de la carpeta SOA:



Este archivo XML va a definir el orden en que se van a ejecutar las válvulas. Aquí lo único que hay que colocar es el nombre de las clases que hemos creado en el proyecto Java (completamente calificadas): en mi caso excelvalves.ExcelToCsv, que fue el nombre que le puse a mi clase donde implementé la válvula. Aquí podemos agregar una o más, dependiendo de nuestras necesidades de implementación.


Finalmente, vamos a agregar en el archivo de configuración del adaptador (JCA), la referencia hacia el Pipeline: <property name="PipelineFile" value="ExcelPipeline.xml"/>




Después de esto, ligamos el adapter a un proceso BPEL. De tal suerte que nuestro compuesto queda de la siguiente forma:


Debajo de la carpeta SCA-INF/lib, debemos colocar el JAR generado de nuestra válvula (el que generamos en el proyecto Java).

Desplegamos el proyecto del compuesto a nuestra infraestructura y lo probamos colocando un archivo de Excel en la ruta que configuramos en nuestro File Adapter.

Deberá iniciarse una instancia y aparecer lo siguiente en nuestros logs:


En Enterprise Manager podremos ver que la instancia se ha ejecutado correctamente:


Los detalles de la traza:


En este caso el BPEL no hace otra cosa sino un assign de la entrada a una variable para posteriormente terminar:


Observamos que los datos provenientes del Excel han sido asignados de manera correcta a la variable:


Comprobamos que todo se haya realizado bien, comparando con los datos de nuestro archivo de Excel:


Resumen


  • Las válvulas pueden servir para pre y/o post procesamiento (archivos de entrada y/o de salida).
  • Las válvulas serán ejecutadas en el orden que definan dentro del pipeline.
  • El pipeline a usar se configura dentro del archivo JCA del adaptador.
  • El pipeline se define en un archivo XML.
  • Las clases de pre y/o post procesamiento se implementan en Java y reciben como entrada un InputStream.
  • Se pueden utilizar frameworks adicionales dentro de las clases Java que implementan la lógica de nuestras válvulas. En mi caso utilicé Apache POI para el procesamiento del archivo Excel (https://poi.apache.org/).
  • El JAR que contiene la implementación de las válvulas se debe incluir en el proyecto (compuesto, OSB) que lo utiliza. Para el caso de un compuesto, lo ponemos debajo de SCA-INF/lib.

lunes, 14 de noviembre de 2016

Oracle Developer Cloud Service Demo

Oracle Developer Cloud Service

Para empezar, vamos a explicar de qué se trata esta nube. Oracle Developer Cloud Service es un ambiente de hosting en la nube. ¿Qué es lo que se sube a esa nube? Proyectos de desarrollo de software.
En esta ocasión, vamos a tomar el rol de ingeniero de software. Una de nuestras tareas va a ser crear un ambiente en la nube de Oracle, para el desarrollo de proyectos Java. Debemos probar la creación de proyectos y administración de incidentes en la nube, así como probar las características de administración del ambiente.
En esta nube podemos tener el rol de administrador o desarrollador. Casi todas las tareas que vamos a cubrir pueden ser realizadas por ambos roles. Sin embargo, algunas de ellas sólo pueden ser ejecutadas por administradores.
Entre otras cosas, básicamente lo que ofrece esta nube es lo siguiente (de acuerdo al fabricante):
1.      Administración de issues
2.      Desarrollo ágil
3.      Repositorio de código fuente
4.      Build del software
5.      Revisión de código
6.      Colaboración vía Wiki
7.      Despliegue de servicios
Sin más, vamos a pasar al uso de la nube y de sus características. Para esto, tendremos que ingresar a través de la consola de Oracle Developer Cloud Service, con las credenciales que nos han proporcionado para el acceso.

Crear un proyecto nuevo

Para crear un nuevo proyecto basta con presionar el siguiente botón:

En la sección de detalles del proyecto, debemos dar un nombre y descripción del proyecto. A continuación, vamos a seleccionar el tipo de seguridad. Los proyectos privados son accesibles únicamente para miembros. En los proyectos compartidos, tanto el código, la wiki, los issues y builds del proyecto están disponibles para cualquier miembro del dominio de identidades de la organización.

Se pueden crear proyectos vacíos, o bien, elegir una plantilla. Si creamos un proyecto a partir de una plantilla, estaremos copiando todos los artefactos: repositorios GIT, configuración de builds y despliegue, páginas de la wiki, etcétera.
En nuestro ejemplo, lo haremos a través de una plantilla:

Por default, en las propiedades del proyecto podemos elegir un estilo de la wiki (Textile, Confluence o Markdown). Todas las wikis del proyecto usarán este estilo. Nosotros elegimos Textile.
Al seleccionar el repositorio inicial, debemos especificar su configuración. Aquí elegimos la opción de inicializar el repositorio con un archivo README.
Si se crea el proyecto a partir de una plantilla, tendremos que especificar algunas otras propiedades.
Al finalizar todo esto, presionaremos el botón Finish:

A continuación, veremos una página que muestra el progreso de la creación de nuestro proyecto. Esto tomará algunos instantes en finalizar:

Una vez que el proyecto es completamente aprovisionado, el sistema nos llevará a la página inicial. Esto nos mostrará los tabs que se muestran en la siguiente imagen. El tab de administración se mostrará únicamente si somos dueños del proyecto:

En esta pantalla podemos explorar algunas de las opciones, podemos esconder el panel de la izquierda para dar una mejor visibilidad del proyecto. También podemos ver el feed en el panel central, volver al menú inicial de Oracle Developer Cloud Service, explorar las características de los repositorios de Maven y Git, gráficas y estadísticas del proyecto, entre otras cosas.

Agregar usuarios al proyecto

Cuando iniciamos un proyecto, uno de los primeros pasos es agrega usuarios al proyecto. Para esto es necesario hacer click en el tab Team del lado derecho. Después debemos elegir New Member:

Aquí podemos agregar un usuario como miembro o como dueño del proyecto. De igual forma, si queremos agregar más de uno, debemos seleccionar la opción de usuarios múltiples. Lo anterior nos permitirá agregar más de un usuario al mismo tiempo:

Nota importante: los usuarios del proyecto deben pertenecer a la organización para poder ser asignados. De lo contrario recibiremos un error como este:

Administración del código con un repositorio Git

Oracle Developer Cloud Service ya provee un repositorio Git para la administración del código. Es posible utilizar un cliente de Git para interactuar con el repositorio. La integración de Git se puede hacer directamente con el IDE (OEPE, Oracle JDeveloper, NetBeans).
Del lado derecho de la página principal del proyecto, podemos encontrar los repositorios del proyecto:

Creación de issues

Ésta nube de Oracle tiene incluído un sistema de administración de issues basado en nube, para el equipo de desarrollo. Es posible definir issues y asignarlos a algún miembro del equipo. Por ejemplo, podemos crear issues para:
1.      Sugerir mejoras
2.      Especificar tareas
3.      Reportar defectos
4.      Definir nueva funcionalidad
5.      Asociar transacciones de código con issues
Para acceder al sistema de administración de issues, debemos elegir ésta opción en el panel del lado izquierdo:

Para crear un issue, es necesario presionar el siguiente botón del lado derecho de la pantalla:

Debemos llenar algunos datos relacionados con el issue, como se muestra a continuación. Aquí podemos catalogar el issue como defecto, tarea o característica. Para este ejemplo elegimos tarea:

Una vez que presionamos el botón de crear issue, nos aparecerá una breve confirmación en la parte superior de la pantalla. Esto nos indica que el issue ha sido creado.
El siguiente paso es asignar un propietario del issue. En este caso me lo asigné a mí mismo. También agregué un comentario que describe qué es lo que hay que hacer para esa tarea.

Una vez que presionamos el botón de agregar, el comentario estará guardado:

Finalmente presionamos guardar y el issue estará creado.
En la página principal de administración de issues, tendremos lo siguiente:

Desarrollo ágil

El tab agile nos permite organizar y calendarizar issues en sprints y supervisar el progreso.
Para esto, tenemos que dar un click en el tab de agile y después crear un nuevo tablero:

Colocamos los siguientes datos y presionamos el botón para crear el tablero:

Esto nos devolverá a un backlog del proyecto. En este backlog tenemos una única tarea creada, la del issue que generamos con anterioridad. Para poder trabajar con el backlog, debemos crear un sprint. Esto lo hacemos dando click en el botón para crear el sprint. Aquí simplemente colocamos el nombre del sprint:

Una vez que creamos el sprint, es necesario mover los issues del backlog hacia este nuevo sprint. Para esto, damos un click derecho sobre la tarea y esto nos dará algunas opciones. En el caso de nuestro ejemplo, elegimos mover la tarea hacia el sprint que acabamos de crear:

Después de realizar esto, tendremos la tarea asociada a nuestro sprint:

Para iniciar nuestro sprint, debemos presionar el botón que está del lado derecho de la pantalla. Esto nos dará opción de definir las fechas de inicio y fin del sprint. Hay que considerar que cuando usamos una metodología ágil, los sprints típicamente son de un par de semanas de duración, por eso el sistema nos indica las fechas de inicio y finalización del sprint, por default.

Al verificar en el tab de sprints activos, podemos ver que el que acabamos de crear ya se encuentra en este estado y el sistema automáticamente los organiza en columnas, como se muestra a continuación:

Revisión del código

Una de las bondades de esta nube, es que nos permite tener absoluto control de los issues a través de la integración del repositorio de Git.
Utilizando las pestañas de Merge Requests y Code, es posible gestionar el ciclo de vida de los issues, así como de realizar un monitoreo del estado de cada uno. Entre otras opciones, podemos realizar lo siguiente:
1.      Copia de un branch hacia uno nuevo, que es donde atenderemos las solicitudes de cambios.
2.      Asociación de los issues abiertos a ese nuevo branch de código.
3.      Modificación del código para resolver el issue o la solicitud de cambio.
4.      Merge de los cambios del branch de trabajo hacia el branch principal del código.
5.      Commit de los cambios.
6.      Adicional se pueden aceptar o rechazar los cambios de acuerdo a la revisión del código.
Al realizar el commit de los cambios, tenemos la opción de cambiar de estatus el issue asociado al repositorio de código. En nuestro caso, al confirmar los cambios en el repositorio principal, podemos observar que el issue que teníamos abierto, ha sido marcado como resuelto.

El último paso es cerrar o terminar el sprint. Como era un único issue el que teníamos asociado al sprint, ahora procederemos a cerrarlo. Esto lo haremos presionando el botón de completar sprint. Nos saldrá una ventana de confirmación, donde aceptaremos la acción:

Lo que veremos a continuación es una pantalla donde nos da algunas estadísticas del estatus del sprint. Verán algo como lo siguiente:

Si observamos la página principal del proyecto, veremos que en el feed se ven reflejadas todas las actividades que hemos realizado hasta el momento:

Uso de la Wiki

Uno de los aspectos interesantes de esta nube es la integración de una Wiki lista para usarse. Podemos usar esta Wiki para crear documentación y colaborar con algunos otros miembros del equipo.
Para acceder a la Wiki, elegimos la opción en los tabs del lado izquierdo de la pantalla. Inicialmente no tenemos Wiki para este proyecto, por lo que veremos una pantalla como la siguiente:

Algo que me pareció muy interesante de esta funcionalidad, es que es un tanto inteligente. Cuando generé la primera página de la Wiki, puse dentro de la descripción del texto la palabra issue 1.

Al guardar la entrada de la Wiki, esto se convirtió automáticamente en un hipervínculo hacia el detalle del issue que generamos con anterioridad.

              
Si damos un click encima del hipervínculo, nos llevará al detalle del issue. Me parece que esta forma de generar documentación es muy simple y práctica de usar.

Ahora en la sección de Wiki, tendremos la que hemos creado recientemente:

Integración continua

Cuando creamos un proyecto en Oracle Developer Cloud Service, tenemos aprovisionadas todo lo necesario para realizar el build. Si queremos subirnos al tren de la integración continua, podemos automatizar e integrar ambientes de pruebas, recibir retroalimentación inmediata o desplegar hacia alguna nube: Oracle Java Cloud Service, Oracle Application Container; o bien, a algún ambiente local.
Para hacer uso de esta característica, debemos elegir la opción de build del lado izquierdo del panel:

Para nuestro ejemplo, elegiremos JDK 1.8:

Es posible ejecutar los pasos que nosotros ocupemos para realizar el build de nuestro proyecto. Esto es una característica muy interesante ya que podemos elegir entre lo siguiente:
1.      Ejecutar un Shell
2.      Invocar Ant
3.      Invocar Maven 2
4.      Invocar Maven 3
5.      Invocar Gradle
6.      Invocar NodeJS
7.      Copiar artefactos
En nuestro caso elegimos la opción de ejecutar un Shell:

Después de realizar el build, también hay varios pasos que podemos ejecutar. Algunos que me parecen muy interesantes son: la integración nativa para realizar el despliegue del proyecto en Oracle Cloud Service, publicar un reporte de pruebas de JUnit o la misma documentación de Java.

Salvamos nuestro job y lo ejecutamos:

Una vez que el build termina de ejecutarse, veremos un resumen parecido al siguiente:

Podemos observar que aquí se encuentra el archivo hello.out que definimos en las tareas del build del proyecto. Si damos click en este archivo, se descargará a nuestro equipo local. Podemos explorar el contenido:

Igualmente, si damos un click en la consola, podremos observar todas las tareas que fueron ejecutadas en el build. Si somos un poco observadores, nos daremos cuenta que detrás de las cámaras, se está ejecutando Hudson como nuestro servidor de integración continua. Esta integración entre la nube de Oracle y Hudson es nativa, nosotros no tuvimos que realizar ninguna configuración adicional, sino que fue aprovisionado de manera automática:

Si vamos a la página principal de jobs, se deberá ver como sigue:

Conclusiones

En conclusión, la nube de Oracle Developer Cloud Service (que a menudo viene incluida con el uso o contratación de algunas otras nubes: Oracle Application Container, por ejemplo), es una nube que nos facilita el desarrollo colaborativo, nos proporciona características de integración con Git, DevOps (Maven, Gradle), integración continua (Hudson), Wiki, y algunas otras características.
Es una muy buena opción, considerando que es gratis con el uso de alguna otra nube de Oracle. Sin duda proporciona características que podríamos y deberíamos emplear en los proyectos de desarrollo de software. Está bien pensada para el uso de metodologías ágiles y nos da una buena cantidad de características de caja para estos propósitos.

Considerando que en los proyectos de desarrollo tradicionales no tenemos orden alguno (o al menos a la mayoría de nosotros nos pasa esto en nuestro día a día), sin duda nos proporciona características valiosas que como desarrolladores nos ayuda a organizar mucho mejor el control del código, el seguimiento a los requerimientos y defectos encontrados en el código, el uso de una metodología (dejen ustedes ágil, con que usemos algún tipo de metodología tenemos suficientes beneficios), entre otras muchas que podrían ser de utilidad.