jueves, 5 de diciembre de 2013

Como utilizar la plataforma WSO2, parte 2

En la entrada anterior de esta serie, parte1, vimos el caso de estudio de una aplicación simple para la gestión de las actividades de un banco, la cual fue desarrollada inicialmente en PHP y MySQL. Pero cuando esta aplicación fue puesta en producción surgieron nuevos requisitos, por lo cual en la presente entrada se muestra como rediseñar la arquitectura del sistema usando los productos de WSO2, que proporcionan una manera eficiente de resolver esos problemas [1].

Por lo general, cuando las personas piensan acerca de los servicios web, tienen la falsa idea de que es algo que solo se debe usar para aplicaciones de alta complejidad técnica en grandes compañías. Es por eso que muchos programadores prefieren ir con lenguajes simples como PHP. Otro hecho es que los desarrolladores han oído historias de horror de muchos fracasos de proyectos SOA, y es por ello que no estudian temas de SOA. Pero esas personas están equivocadas. Por supuesto, si nos fijamos en los productos de, por ejemplo Oracle, relacionados con SOA en realidad son muy complejos. Para usar esos productos debes descargar muchos gigabytes solo para enviar un mensaje. Y no se puede esperar nada más de una empresa que está dirigida por abogados, no por ingenieros de software.

La elección de la tecnología adecuada.

Cuando usted está eligiendo una tecnología para la implementación de un proyecto, tradicionalmente se reduce a elegir entre unas pocas opciones, aprovechando lo que ya tiene en su compañía. Como por ejemplo, si tiene un servidor de aplicaciones, optara por usarlo. Es probable que también opte por elegir una tecnología con la cual esté familiarizado el equipo de desarrollo. Hoy, sin embargo, estas opciones están cambiando. ¿Qué tecnología le da el mejor tiempo de respuesta a la hora de implementar un proyecto? También hay que gestionar la flexibilidad y aspectos de mantenimiento. La capacidad de adaptarse a los nuevos requisitos con facilidad es muy importante. Cuando usted tiene que implementar un nuevo módulo para la aplicación (sin dejar de hablar en términos de nuestro ejemplo banco) si se toma 6 meses para lograrlo, entonces no es eficiente.

Vamos a recapitular nuestros nuevos requisitos y pensar cómo podemos rediseñar con eficiencia el sistema.

  1. Su aplicación ahora debe soportar múltiples interfaces de usuario en varios dispositivos.
  2. Tienen que abstraer algo de lógica de negocio en un conjunto de reglas.
  3. La información debe ser fácil de integrar en otros sistemas.
  4. La información debe ser fácil de exponer de forma segura a diferentes sistemas y personas. Debe existir un mecanismo de acceso a la información basado en roles.
  5. Debe ser capaz de identificar patrones de las transacciones que se realizan.
  6. Debe ser capaz de extenderse para adoptar e integrar sistemas legados.
  7. Tienen que ser capaces de exponer y enviar información de forma fiable sin tener ninguna pérdida de mensajes en el sistema.
  8. Cualquier parte del sistema debe ser capaz de escalar fácilmente.
  9. 9. Tiene que tener un sistema de vigilancia que sea fácil de configurar para la adición de los nuevos módulos, así como el control de la configuración distribuida que vamos a tener.
  10. Al entrar en funcionamiento y tener una configuración distribuida tenemos que ser capaces de asegurar la comunicación que está pasando entre los módulos y sistemas externos.

Cómo los productos de WSO2 resuelven este problema.

Vamos a empezar con la interfaz visual. WSO2 tiene las tecnologías que se pueden utilizar para desarrollar la interfaz de usuario, el núcleo y middleware de la aplicación. Hay varias maneras en que puede desarrollar la interfaz de usuario. Si usted está utilizando la tecnología de WSO2 la forma más fácil de desarrollar la interfaz es utilizando Jaggery, que es un framework JavaScript del lado del servidor, similar a NodeJS. WSO2 está desarrollando un nuevo producto llamado “WSO2 User Engagement Server (UES)”, que permite crear interfaces arrastrando y soltando componentes. Arrastre una tabla y coloque la URL que tiene los datos y ya está listo, los datos serán obtenidos y mostrados. Aunque la página web del producto aún no ha sido creada, la versión beta está disponible! Puedes descargarlo desde aquí. Descomprimir y ejecutar el fichero script wso2server.{ Sh, bat } en la carpeta bin. Una vez iniciado el servidor puede acceder al portal, desde su navegador en la dirección: http://localhost:9763/portal/. La configuración predeterminada de usuario / contraseña para iniciar sesión es: admin / admin. Pruébalo, ¡es increíble!

Ya tiene la interfaz visual y también puede permitir a los usuarios crear cuadros de mando (dashboards) personalizados. ¿Y ahora qué? Ahora es necesario tener un conjunto de APIs que implementan las funcionalidades del negocio. Cuando usted tiene eso es fácil conectar diferentes aplicaciones / interfaces / servicios para obtener datos. Si va a conectar dispositivos móviles, es posible que desee manejar datos JSON para facilitar su procesamiento. Como estas APIs pueden estar expuestas no sólo a las aplicaciones internas, sino también a las aplicaciones externas, entonces usted necesita para tener seguridad. También necesitara tener capacidad de monitoreo para supervisar quién está utilizando una API, cual es la frecuencia de uso y el tiempo de respuesta. Para ello usted puede utilizar: “WSO2 API Manager” que permite la creación y gestión del ciclo de vida de la API a través de una consola web de fácil administración.

Las API necesitan comunicarse con un servicio o un conjunto de servicios que implementan funcionalidades de negocio. Dado que en nuestro ejemplo estamos tratando con módulos como el depósito a plazo fijo, créditos y cheques, pues cada uno de ellos se puede implementar como un servicio y agrupar todas las funcionalidades relacionadas con ese servicio. Los servicios web animan a hacer todo de una manera sin estado, así que es fácil de escalar cuando ello sea necesario. La implementación del servicio se puede hacer en Java y alojarlo en el servidor de aplicaciones (Application Server). El servidor de aplicaciones se está ejecutando en una instancia de Tomcat empotrado. Ahora usted tiene la lógica de negocio implementada y alojada en el servidor de aplicaciones. El siguiente paso es utilizar el bus de servicios empresariales (Enterprise Service Bus) que permite la comunicación entre los componentes que forman parte el sistema y actúa como un punto que permite integrar diferentes sistemas. Los sistemas bancarios legados de nuestro ejemplo.

A continuación, se puede desarrollar una capa de servicios de datos en la parte superior de la base de datos que estaba utilizando, para exponer esos datos como servicios web. Así, al implementar servicios de negocios, estos pueden hablar con los servicios de datos para realizar operaciones a nivel de datos. Esto proporciona una interfaz limpia para interactuar con la base de datos y hacer la lógica de aplicación mucho más simple. Usted no tendrá que utilizar las llamadas JDBC o utilizar una capa de persistencia / ORM como Hibernate. Cuando usted está accediendo a los datos en la base todo lo que tiene que hacer es otra llamada de servicio web. A continuación, la capa de acceso a datos puede tener su propio mecanismo de seguridad independiente de los demás sistemas. Esto es fácil con el servidor de servicios de datos (Data Services Server) donde se puede exponer a cualquier tabla de base de datos o una consulta personalizada como un servicio web.

Ahora vienen las reglas de negocio. Se puede utilizar el Servidor de Reglas del Negocio (Business Rules Server, BRS) para crear un conjunto de reglas reutilizables de la que la lógica empresarial. BRS expondrán todas sus reglas de negocio como un servicio web. Por lo tanto, cuando usted está pidiendo una regla de negocio para evaluar, todo lo que tiene que hacer es llamar a otro servicio web. Veamos cómo luce esta solución:

clip_image002

Como se puede ver en la imagen hemos incluido la herramienta Business Activity Monitor (BAM) para la supervisión. Los componentes API Manager, ESB, AppServer etc, tienen agentes de publicación que envían los datos estadísticos sobre las invocaciones de servicio al BAM. Usted sólo tiene que dar la información de conexión y los detalles sobre estadísticas de los servicios serán recogidos en el BAM. A continuación, puede configurar UES para mostrar un panel personalizado de todos o un subconjunto de los eventos. Una de las ventajas de esta solución es que puede escalar cada uno de los componentes sin tener un efecto adverso sobre otras partes del sistema. Por ejemplo si el servicio de cuenta de ahorros está atrayendo una gran cantidad de tráfico, puede colocar un clúster el servidor de aplicaciones. Si el sistema está generando una gran cantidad de eventos que se envían a BAM entonces usted puede poner en un clúster el BAM y así sucesivamente.

En el diagrama de arriba hay un ESB independiente que se ocupa de los aspectos de integración, y también está allí para proporcionar y conectar con los sistemas heredados que se utilizarán.

Fuera de los requisitos que hemos hablado, hay algo más que no hemos considerado en la imagen de arriba. Que está relacionado con la identificación de los patrones acerca de las transacciones fraudulentas de tarjetas de crédito. Para ello podemos utilizar WSO2 Complex Event Processing Server (CEP). Como el CEP analiza flujos de eventos, el lugar natural para colocar el CEP es dentro del BAM. Porque nosotros de todos modos estamos enviando todos los eventos al BAM para fines de control. A continuación, puede configurar diferentes alertas en base a los criterios que necesita.

Conclusión

En resumen, hemos puesto el ejemplo de una aplicación web sencilla y luego vimos como los requisitos aumentaron con la necesidad de integrar sistemas adicionales y la ampliación de las diferentes partes, analizando las posibles dificultades técnicas que se introducen para hacer esos cambios. Entonces explicamos que si usted piensa en esos problemas de forma anticipada, puede diseñar arquitectura diferente para el sistema, que se ajuste bien a las necesidades. Y por último se mostró cómo algunos de los productos de WSO2 resuelven, sin mucho esfuerzo, esos problemas difíciles.

{ Leer Más }


martes, 26 de noviembre de 2013

Preparando datos para exportar a excel sobre CodeIgniter

En este artículo les voy a poner un ejemplo un poco más completo de cómo generar un excel con información existente en nuestra base de dato. Recomiendo leer primero el artículo “Importando y exportando excel sobre CodeIgniter”, donde presenté la biblioteca PHPExcel para importar y exportar ficheros de hojas de cálculo (excels).

En dicho artículo expliqué cómo instalar esta biblioteca, y cómo en mi caso creé una biblioteca que actúa como interfaz con la PHPExcel, con dos funciones “import” y “export”. En aquel entonces puse un ejemplo de código de exportar en el que solamente se ponía un valor en una celda. Modificando el código para hacerlo cíclicamente quedaría así (en $table vienen los datos sacados de la BD):

function export($table)
{
$objPHPExcel = new PHPExcel(); //creando un objeto excel
$objPHPExcel->getProperties()->setCreator("Yanoski")… //propiedades
$objPHPExcel->setActiveSheetIndex(0); //poniendo active hoja 1
$objPHPExcel->getActiveSheet()->setTitle("Hoja1"); //título de la hoja 1

//llenando celdas
$column = 0;
$row = 1;
foreach ($table as $record)
{
foreach ($record as $value)
{
$objPHPExcel->getActiveSheet()->setCellValueByColumnAndRow($column, $row, $value);
$column++;
}
$column = 0;
$row++;
}

//poniendo en negritas la fila de los títulos
$styleArray = array('font' => array('bold' => true));
$objPHPExcel->getActiveSheet()->getStyle('A1:Z1')-> applyFromArray($styleArray);

//poniendo columnas con tamaño auto según el contenido, asumiendo N como la última
for ($i = 'A'; $i<= 'N'; $i++)
$objPHPExcel->getActiveSheet()->getColumnDimension($i)->setAutoSize(true);

//código de exportar (ver artículo antes mencionado)
}

 


Como puedes ver todo se reduce a hacer un recorrido anidado al arreglo bidimensional $table, donde para cada fila ($record) accedo a cada valor de columna ($value) y lo inserto en la celda $column,$row, valores que voy incrementando convenientemente.

El uso desde un controlador sería sencillamente:

function export_data()   //en el controlador
{
$table = $this->my_model->get_table();
$this->load->library('excel_pdf_manager');
$this->excel_pdf_manager->export($table);
}

 


¿Dónde está el truco entonces? En el modelo. Es ahí donde realmente se formatea el arreglo bidimensional “$table” de forma que coincida con lo que quieras exportar. Los dos segmentos de código que puse arriba son genéricos para cualquier tabla de base de datos. Si quisieras exportar varias tablas de la BD llamarías la línea $table = $this->my_model->get_table() para cada modelo diferente.

Un ejemplo de conformación del arreglo $table sería como sigue, suponiendo una tabla de usuarios que contiene nombre, apellidos, correo electrónico y nombre de usuario, con su correspondiente modelo que llamaré “my_model” para que ajuste con el código anterior:

 

function get_table()   //en el modelo my_model
{
//datos a seleccionar
$this->db->select(users.ID, users.NAME, users.SURNAME, users.EMAIL, users.USERNAME');

//encabezados de las columnas
$headers = array('No', 'Nombre', 'Apellidos', 'Correo electrónico', 'Usuario');

$query = $this->db->get(' users ');
if ($query->num_rows > 0)
{
$table[] = $headers;
$i = 1;
foreach ($query->result() as $row)
{
$row->ID = $i;
$table [] = $row;
$i++;
}
return $table;
}
else
return null;
}

 


Aquí, dos cosas importantes: primero, hacer un select donde acomodas las columnas en el orden deseado y segundo, agregar una fila con los encabezados de las columnas que se pone como primera del arreglo “$table”, y es la fila que se pondrá en negritas.

Como detalle, para no mostrar los ID de los usuarios en el excel (que al final suele ser un autonumérico que actúa como llave de la tabla), he puesto en su lugar un número incremental que comienza en 1, así siempre saldrá en la primera columna del excel un ordinal, independientemente de cual sea el ID del usuario.

Hasta aquí cómo formatear los datos para exportarlos a un excel. En un próximo artículo mostraré el proceso inverso, de importar datos de un excel y verterlos en una tabla de la base de datos.

{ Leer Más }


viernes, 15 de noviembre de 2013

Como utilizar la plataforma WSO2, parte 1.

El objetivo de esta entrada es guiarlo a través del proceso del pensamiento para desarrollar una aplicación simple, en un primer momento usando PHP y MySQL y luego se explicara cómo usted puede rediseñar la arquitectura del sistema usando los productos de WSO2. Cómo y por qué ellos se usan. Se explica a alto nivel para que usted pueda seguirlo fácilmente. Luego de desarrollar la aplicación web sencilla, simularemos un cambio en los requisitos, que trae asociado ciertos problemas que usted tiene que considerar y cómo los productos de WSO2 proporcionan manera rica y fácil de resolver esos problemas [1].

Diseño de la aplicación

Antes de revisar la lista de productos de WSO2 y qué ellos pueden hacer, veamos algunos puntos sobre el diseño de la aplicación. Si usted es un diseñador web probablemente esté familiarizado con los Sistemas de Gestión de Contenido (CMS, por sus siglas en inglés: Content Management System) como por ejemplo: Wordpress/Drupal/Joomla… Si va a desarrollar un sitio web relativamente simple todo lo que usted tiene que hacer es crear un tema personalizado, poniendo el diseño, los logos y los colores correctos. Usted estará dedicando la mayoría de su tiempo en los aspectos de la interfaz visual de usuario y permitiendo que el CMS que usted está usando se encargue del proceso de adicionar/actualizar los contenidos del sitio de forma fácil.

Entonces hay sistemas en los cuales usted no quiere usar un Sistema de Gestión de Contenido. Este es el caso de las aplicaciones web simples, donde usar un CMS complica las cosas. Para esos casos, usted necesitaría que un lenguaje de programación simple del lado del servidor como PHP y un poco de HTML/CSS para darle completar la interfaz. La mayoría de aplicaciones web comienzan así. Usted comienza con un montón de páginas PHP y entonces cuando hay una necesidad de interactuar con la base de datos que usted escribe una clase "ligera" para la comunicación con la BD, luego instancia esa clase y lleva adelante las operaciones de acceso a datos. Entonces hay un rango entero de patrones en esta área que documenta las mejores prácticas en lo que se refiere a aplicaciones web en vías de desarrollo. MVC, FCP y otros. Entonces hay Frameworks que captan estas mejores prácticas y tratan de proveerle de abstracciones de alto nivel, como por ejemplo: CodeIgniter, CakePHP, ZendFramework, etc.

Así que si usted ha estado trabajando con este espacio durante algún tiempo, los servicios web podrían no tener sentido para usted. ¿Por qué necesita usted servicios web? Por ejemplo: ¿Por qué necesitaría usted algo exponga los datos de una base de datos como un servicio web? Usted diría que eso parece ridículo, cuando usted puede consultar la base de datos usando mysql_query().

“Para que necesito Servicios Web, yo puedo desarrollar una aplicación web mucho más simple usando PHP y MySQL!”

Usted probablemente definiría una arquitectura orientada a servicios Web cuando usted tiene que pensar acerca de la escalabilidad de su aplicación Web. Cuando eso ocurre usted necesita poder tratar partes diferentes del sistema independientemente, para lograr concentrarse en ciertos aspectos funcionales de la aplicación sin tener un impacto adverso en otras partes. Usted necesita diseñar su aplicación de forma que distribuya las funcionalidades en componentes diferentes. Luego usted necesita alguna forma de comunicarse con estos componentes distribuidos del sistema. Usar servicios Web es una de las soluciones a ese problema.

Veamos cómo dan vueltas los requisitos arriba en un proyecto típico del que usted podría tener para ocuparse. Primero podría ser una petición como, necesitamos tener una aplicación Web interna para proporcionarle a una experiencia agradable al usuario de todas nuestras funciones en el banco. Si usted es el encargado de esta tarea, necesitaría analizar detalladamente las funciones del banco y luego desarrollar una aplicación web que tenga todas estas funciones. Al principio podría ser que usted desarrolle un módulo simple como piloto, para ver si tiene éxito o no. Puede ser por ejemplo el módulo de cuentas de ahorros en el banco. Usted analizó los requisitos, uso una BD para transacciones y codifico el sitio usando PHP. Agradable, simple y funcional. Su aplicación piloto tiene una interfaz de usuario agradable, todos están felices y usted recibe la señal de seguir adelante para incluir más funciones. Como, el módulo de depósito fijo, el módulo de procesamiento de la tarjeta de crédito, módulo para tramitar prestamos, etcétera. Para este ejemplo si bien tomó un banco también se aplica a la amplia variedad de sistemas y las compañías.

“Pensar acerca de posibles extensiones a su aplicación, cuadro grande de como su aplicación será usada a largo plazo, cómo jugará junto con las cosas que usted ya tiene en su organización ahorrara gran cantidad de tiempo cuando usted se enfrente con tareas de integración en el futuro”

Desarrollando una aplicación sencilla.

Si usted ha pensado acerca de tener todos estos módulos inicialmente su trabajo es más fácil. En caso de que no usted necesita refactorizar el código y dividirlo en módulos. Usted codifica todo arriba, ajusta la BD, tiene secciones en la interfaz de usuario para todos los módulos y todo es progresivamente agradable. Puede ser que usted pone todos los módulos diferentes en una estructura como esta:

modules/
common/
fixed_deposit/
loans/
savings/
...

Además supongamos que tiene todas las funciones que son comunes para todos los módulos en la carpeta "commons". Ahora, si usted es realmente afortunado, la lista inicial de requisitos ya tenía el requisito de monitorear el sistema entero. Si usted es desafortunado el requisito de monitoreo surgirá cuando usted ha terminado con el sistema. Usted necesita de cierta forma poner en bitácora todas las operaciones que ocurren en el sistema y proveer una interfaz de usuario para monitorear, a la cual puedan acceder los administradores para ver cómo progresa el sistema, uso de datos, qué módulos están siendo utilizando, etcétera. Esto se convierte no sólo un asunto de nivel operacional, sino también en un asunto de la gerencia. Por ejemplo si la tasa de los depósitos fija está de baja, sería útil hacer un poco de mercadeo y ofertar negocios lucrativos para atraer más depósitos a plazo fijo. Usted no ha pensado acerca de monitoreo, ahora usted tiene que sumar código para poner en bitácora esta información en sus módulos. Luego cree una consola. Puede ser usted puede crear una "pestaña" separada para esta información en su interfaz de usuario que es visible sólo para los usuarios de tipo admin. Su aplicación podrá quedar algo así como lo siguiente.

clip_image002

Nuevos requisitos

Ojalá en este punto todas las personas fueron felices con las funcionalidades de la aplicación por los siguientes 10 años. Esto rara vez ocurre en la vida real. Lo que seguramente ocurriría es que cuando usted puso el sistema en operación toda clase de requisitos puede surgir. Veamos un ejemplo de estos:

· Necesitamos poder tener la interfaz de usuario para hacer monitoreo desde dispositivos iPad, todos las personas de operaciones deberían tener esta aplicación del iPad/iPhone para ver cómo funciona el sistema.

· Necesitamos tener un conjunto de reglas del negocio, que sean editables por los usuarios. Eso debe hacerse de forma simple, no editando código PHP, por ejemplo, cuando la tasa de interés se acorta.

· Necesitamos que la información de los depósitos fijos sea integrada para la aplicación nueva que construimos subcontratando a otra compañía.

· Necesitamos exponer un subconjunto de información acerca de los préstamos y los clientes para otros bancos para crear una lista negra de malos clientes.

· Necesitamos que una forma rápida se detecten transacciones fraudulentas en nuestras operaciones con tarjetas de crédito.

· Este sistema es genial, necesitamos integrarlo en los otros sistemas viejos que tenemos en nuestro banco. Tenemos algunos sistemas viejos que necesitamos para obtener datos y mostrarlos en este nuevo sitio Web.

· Vamos a usar un nuevo sistemas de procesamiento de cheques de otro banco, es por ello que necesitamos enviar todo nuestra información relacionada con los cheques al sistema, de forma segura a través de internet. Tenemos que asegurarnos que enviamos esta información en una forma fidedigna.

Análisis del problema

Si usted se pone a pensar, en un principio el sistema que usted desarrolló era simple, así que usaba PHP y una base de datos, pero ahora ha cambiado mucho y que ahora han surgido otras preocupaciones. Si por ejemplo, el módulo de cuentas de ahorro es usado en exceso y genera una gran cantidad de tráfico en el sistema, éste no sólo afecta ese módulo sino también al sistema entero. Si el sistema entero está apagado entonces ese es un impacto grande en el negocio. Eso no es lo que usted quiere. La aplicación PHP que consideramos inicialmente es monolítica. Entonces debería dividir esta aplicación en varias. Una opción para hacer esta división es usar XML-RPC para hacer llamadas de procedimiento remoto. Cuando usted divide su aplicación en varios pedazos y usa un montón de máquinas para alojarlos, allí surgen preocupaciones adicionales. Por ejemplo la seguridad. Usted no puede hablar entre los módulos con mensajes simples del texto porque la información que usted enviará de acá para allá es sensible. Estará relacionado con información del cliente, cuentas, información de la tarjeta de crédito etcétera. Así es que usted tiene que enviar las funciones que usted será el anfitrión de otras máquinas a través de HTTPs. Si usted necesita encriptación de datos, usted tiene que implementar en todos los componentes diferentes teniendo un gran número de duplicación de código. Usted tiene que mantener y sean cuidadoso con todo este código y probar cada componente. Luego usted tiene que volver a pensar acerca de monitorear la información. De la misma forma debe repensar el conjunto de reglas del negocio. Ahora usted se ha separado todo, entonces qué haría con ese módulo de cuentas de ahorros que atrajo una gran cantidad de tráfico? Usted puede tener un montón de servidores Apache corriendo el módulo de la cuenta de ahorros y hace un balanceador de carga entre esos. Si usted ha usado sesiones PHP, y si sus funciones confían en estado que ha almacenado en la sesión actual, entonces usted tiene que permitir copia de sesión entre los nodos o cambiar su código para hacerlos sin estado. Luego, cuando usted tiene todos estos cambios, usted tiene que probarlo correctamente para evitar incongruencias y lograr la exactitud funcional. Son un montón de cosas para considerar para una aplicación simple PHP.

Ahora usted entiende el problema y las complicaciones que todos los requisitos /factores adicionales introducirán, en la próxima entrada les explicaremos como usar plataforma WSO2 para resolver esta situación.

{ Leer Más }


lunes, 28 de octubre de 2013

Envío de correos sobre CodeIgniter

 

En el artículo anterior “CKEditor + KCFinder sobre CodeIgniter”, te comentaba sobre la integración de una interfaz WYSIWYG sobre Codeigniter. En este artículo te hablaré sobre la utilidad del CKEditor en combinación con la clase email de CodeIgniter para hacer un formulario de envío de correos.

En la ayuda de CodeIgniter puedes encontrar que con la biblioteca email puedes hacer:

$this->load->library('email');

$this->email->from('your@example.com', 'Your Name');
$this->email->to('someone@example.com');
$this->email->cc('another@another-example.com');
$this->email->bcc('them@their-example.com');
$this->email->attach('/path/to/photo1.jpg');
$this->email->attach('/path/to/photo2.jpg');
$this->email->subject('Email Test');
$this->email->message('Testing the email class.');
$this->email->send();

Está muy claro: cargas la biblioteca, defines remitente, destinatarios, adjuntos, título y cuerpo del mensaje, y lo mandas. Es todo lo que necesitas para enviar correos.

Para facilitar las cosas, en nuestro caso hicimos una biblioteca “mail_manager” dentro de application/libraries/mail_manager.php y un fichero de configuración en application/config/mail_config.php.

El fichero de configuración tiene un destinatario FROM por defecto con su nombre, y el tipo de correos (html). Así que en el constructor de mail_manager se carga la biblioteca email de Codeigniter, se carga el fichero de configuración mail_config, y se inicializa la clase email de CodeIgniter con la configuración cargada.

Adicionamos entonces una función send a mail_manager que básicamente recibe los argumentos y hace las llamadas a email indicadas en el grupo de código de arriba.

send($from, $name, $to, $subject, $body, $cc='', $bcc='', $attach_array='')

Con esto ya se pueden mandar correos automáticos, por ejemplo cuando alguien se registra se le envía el correo de “Usted se ha registrado…”.

En otra parte necesitamos que el usuario enviara correos con un formulario. Aquí utilizamos entonces el CKEditor para lograr la siguiente interfaz:

clip_image002

Figura 1 Interfaz de envío de correos

Claro que para esto creamos un controlador “emailer” en cuyo constructor se configura un CKEditor y se envía una instancia del mismo para esta vista (ver artículo CKEditor + KCFinder sobre CodeIgniter).

El botón “Para” de la vista abre una ventana popup donde se pueden seleccionar destinatarios; y el botón “Buscar” permite seleccionar un atachado, que con un poco de jquery modifica la vista cada vez que se selecciona un adjunto, permitiendo eliminarlo nuevamente u obtener una vista previa de él, o seleccionar un nuevo atachado (figura 2).

clip_image003


Figura 2 Detalle de inserción de atachados

Cuando se da “Enviar”, el controlador emailer recibe los inputs y llama a la función “send” de la biblioteca mail_manager.

Con esto quedó terminado nuestro formulario para envío de correos, una mezcla de componentes visuales de html y bibliotecas y utilidades de CodeIgniter para lograr una interfaz agradable y funcional.

{ Leer Más }


lunes, 21 de octubre de 2013

PL/pgsql

 

Vamos a abordar un tema muy importante para el desarrollo de cualquier proyecto, en este caso visto desde la parte de las base de datos y es precisamente el uso los procedimientos almacenados, en caso de postgreSQL las funciones, en otras palabras vamos a utilizar el lenguaje procedural PL/pgSQL de PostgreSQL en la resolución de problemas.

image


Ventajas

  • Cuando la ejecución del procedimiento ocurre en el servidor, es probable que aumente el rendimiento de nuestra aplicación al no tenerse que mandar datos entre el cliente y el servidor, y no tener que procesar resultados intermedios en el cliente para obtener el resultado final.
  • Al tener la lógica de la aplicación implementada en la Base de datos no tendremos que implantarla en los clientes, con el significativo ahorro de líneas de código redundante.
  • Si tenemos diferentes tipos de clientes implementados en diferentes sistemas ó lenguajes de programación y a la vez accediendo a la misma base de datos, no tendremos que programar la misma lógica en todos, al estar disponible en la base de datos la solución de nuestro problema.

Los procedimientos almacenados (stored procedures) en PostgreSQL se les llaman funciones, las cuales están almacenadas en la base de datos y listas para ser usadas. En postgreSQL se utiliza para la programación de funciones los lenguajes procedurales.

Lenguajes procedurales

PL/Perl: Es un lenguaje de programación imperativo y permite más control que el álgebra relacional de SQL.

PL/Python: Utiliza el entorno de ejecución de Python restringido. Funciona como un lenguaje de confianza.

PL/Java: Es un módulo libre que trae procedimientos almacenados, disparadores, y funciones para PostgreSQL backend a través de la interfaz estándar JDBC.

Y el PL/pgSQL es muy parecido al lenguaje PL/SQL utilizado por Oracle, es fácil de aprender, potente y siempre está disponible. Es un lenguaje estructurado en bloques y posee como mínimo un bloque principal en el procedimiento almacenado y dentro de este pueden existir sub-bloques. El mismo se puede utilizar para crear las funciones y disparadores (triggers), este último lo explicaremos en próximos artículos.

Además con el PL/PGSQL se pueden añadir estructuras de control SQL, realizar cálculos complejos entre otra serie de operaciones muy importantes para la solución de nuestros problemas.

A continuación vamos a pasar a ver la estructura de una función para entenderla mejor:

CREATE [OR REPLACE] FUNCTION
nombre_funcion([[ argmodo ][ argnombre ] argtipo [,...]])
RETURNS tipo AS $$
[ DECLARE ]
[ declaraciones de variables ]
BEGIN
Codigo
END;
$$ LANGUAJE plpgsql

Es importante señalar que los comentarios se definen /* mi comentario */ y los tipos de datos se declaran por ejemplo id INTEGER;

De todas maneras vamos a cerrar este artículo con un ejemplo muy sencillo pero que ilustra claramente la sintaxis que acabamos de poner.

CREATE FUNCTION sumar (x integer, y integer) RETURN INTEGER AS $$
Declare
Resultado integer;
BEGIN
Resultado:=x+y;
Return resultado;
END
$$ LANGUAJE plpgsql

Las funciones se pueden complejizar tanto como queramos en nuestras soluciones, los exhortamos a que continúen abordando sobre estos temas tan importantes, comiencen a utilizar consultas dentro de las funciones y a practicar el funcionamiento de las mismas.

{ Leer Más }


viernes, 18 de octubre de 2013

CKEditor + KCFinder sobre CodeIgniter

CKEditor

CKEditor es un helper para CodeIgniter creado por Samuel Sánchez, que permite adicionar a nuestros sitios web una interfaz visual como la que se muestra en la figura 1, a modo WYSIWYG. Con este componente se le brinda a los usuarios la posibilidad de introducir texto enriquecido con fuentes y estilos de letras, hipervínculos, imágenes, etc.

clip_image001

Figura 1 Interfaz visual del CKEditor

Para acoplar CKEditor a CodeIgniter, descargas el paquete en [1] y copias el ckeditor_helper.php para tu directorio application/helpers. Luego copias el ckeditor completo para js/ckeditor (ver tutorial completo en [2]).

Una vez hecho esto creas una función en el controlador relacionado con la vista en la que quieras usar el componente, y la llamas en el constructor… esto para que no incluyas todo ese gran código en el constructor de la clase:

public $data = array();         //creación de la variable $data

function __construct()
{
parent::__construct();

$this->configure_ckeditor(); //llamada a la configuración del ckeditor
}

private function configure_ckeditor()
{
//helpers for CKEditor
$this->load->helper('url');
$this->load->helper('ckeditor');

//Ckeditor's configuration
$this->data['ckeditor'] = array
(
//ID of the textarea that will be replaced
'id' => 'content',
'path' => 'js/ckeditor',

//Optionnal values
'config' => array(
'toolbar' => "Full", //Using the Full toolbar
'width' => "550px", //Setting a custom width
'height' => '100px', //Setting a custom height
),

//definición del estilo del ckeditor

);
}

Recorté un poco el código para dejar lo fundamental: primero, creas una variable “$data” global para el controlador, y en la función que configura al ckeditor defines el id del componente visual que será reemplazado por el editor de ckeditor, en este caso se llama “content”.

Hecho esto, en la función que carga la vista deseada pasas la variable $data[ckeditor],

function load_view()
{
$data['ckeditor'] = $this->data['ckeditor'];
$this->load->view('views/my_view.php', $data);
}

Y en la vista, en el lugar donde quieras que te salga el componente, pones el siguiente código:

<?php echo form_textarea(array('name' => 'content', 'id' => 'content')); ?>

<?php echo display_ckeditor($ckeditor); ?>

Con esto lo que estamos haciendo es, que el textarea con id “content” sea reemplazado por el ckeditor que pasamos en la variable $ckeditor (recuerda que en el controlador dijimos que el componente con id “content” sería reemplazado por un ckeditor).

En el controlador capturas el contenido del componente como con cualquier otro:

$content = $this->input->post('content').

KCFinder

Bien, en la primera parte de este artículo he querido introducirte a la instalación del CKEditor sobre Codeigniter, pero la intención final es montar el KCFinder.

Como detalle, en el texto del componente ckeditor puedes insertar imágenes a través del ícono señalado en la figura 2. Esta opción abre la ventana mostrada en la figura 3, donde puedes escoger la dirección de una imagen existente en el servidor.

clip_image002

Figura 2 Opción de insertar imágenes en el texto

clip_image003

Figura 3 Ventana de inserción de imágenes

El problema está en darle a los usuarios la facilidad de subir primeramente imágenes al servidor y a la vez seleccionarlas para insertarlas en el texto del ckeditor. Aquí entra entonces el kcfinder, un explorador de imágenes, archivos genéricos y contenido flash que permite acoplarle al ckeditor los componentes necesarios para subir y seleccionar archivos.

Ojo, no confundir con CKFinder: CKFinder es de pago y KCFinder es la alternativa libre.

Una vez instalado, el kcfinder le adiciona al ckeditor la pestaña “Upload” en la ventana de selección de imágenes (figura 4) que permite subir imágenes al servidor, y adiciona el botón “Browse Server” (figura 5) que permite buscarlas y seleccionarlas para introducirlas en el texto.

clip_image004

Figura 4 Pestaña Upload

clip_image005

Figura 5 Botón "Browse Server"

Para instalar el kcfinder [3] descomprime el archivo kcfinder.zip dentro de /js/ckeditor de forma que quede así: /js/ckeditor/kcfinder.

Luego, en el controlador (en el que estamos usando como ejemplo), se configura la variable de sesión que le especifica a kcfinder el camino en el servidor:

private function configure_ckeditor()
{
$_SESSION['KCFINDER'] = array();
$_SESSION['KCFINDER']['disabled'] = false;
$_SESSION['KCFINDER']['uploadDir'] = 'C:\wamp\www\...';
$_SESSION['KCFINDER']['uploadURL'] = base_url()."images/kcfinder/";

//helpers for CKEditor
$this->load->helper('url');
$this->load->helper('ckeditor');

//Ckeditor's configuration
$this->data['ckeditor'] = array
(
//ID of the textarea that will be replaced
'id' => 'content',
'path' => 'js/ckeditor',

//Optionnal values
'config' => array(
'toolbar' => "Full", //Using the Full toolbar
'width' => "550px", //Setting a custom width
'height' => '100px', //Setting a custom height

'filebrowserImageBrowseUrl' => base_url().'js/ckeditor/kcfinder/browse.php?type=images',
'filebrowserImageUploadUrl' => base_url().'js/ckeditor/kcfinder/upload.php?type=images'
),


//definición del estilo del ckeditor

);
}

Aquí puse en negritas el código adicionado a la función configure_ckeditor. Con esto queda lista la integración del CKEditor con KCFinder sobre CodeIgniter. Puedes obtener una guía más completa de esta integración en [4].

Referencias:

[1] Descarga de CKEditor

http://ckeditor.com/download

[2] Tutorial de instalación de CKEditor sobre Codeigniter

http://kromack.com/developpement-php/codeigniter/ckeditor-helper-for-codeigniter/

[3] Descarga de KCFinder

http://kcfinder.sunhater.com/download

[4] Howto CodeIgniter 2.1 + Ckeditor 3.6.1 + kcfinder 2.51

http://www.hcosta.info/wp/2012/05/howto-codeigniter-2-1-ckeditor-3-6-1-kcfinder-2-51/

{ Leer Más }


jueves, 10 de octubre de 2013

Servicios web (webservices) con SOAP sobre CodeIgniter

(Continuación del artículo Servicios web (webservices) con REST sobre CodeIgniter)

SOAP

En la primera parte de este artículo te comenté sobre el uso de REST sobre CodeIgniter usando la biblioteca “CodeIgniter Rest Server”. A continuación de hablaré sobre el trabajo con la biblioteca nusoap para la implementación de webservices con SOAP sobre CodeIgniter.

La nusoap (versión 0.9.5) puedes descargarla en [2]. En el artículo [1] puedes ver un guía excelente de la instalación de nusoap sobre CodeIgniter. Básicamente es igual a la instalación del Rest Server: copias la carpeta lib de la instalación de nusoap para la carpeta application/libraries (en mi caso le cambié el nombre a la carpeta lib por nusoap_lib), y en ese mismo nivel creas una biblioteca interfaz que hace una llamada a la nusoap, así:

class Nusoap_library
{
function Nusoap_library()
{
require_once('nusoap_lib/nusoap'.EXT);
}
}

Sencilla de instalar. Ahora vamos a crear servicios: siguiendo el mismo tutorial [1] hacemos un controlador con su constructor, un index y un servicio que suma dos números:

class Soapserver extends CI_Controller
{
function Soapserver()
{
parent::__construct();
$this->load->library("Nusoap_library"); //cargando mi biblioteca
$this->nusoap_server = new soap_server();
$this->nusoap_server->configureWSDL("SOAP Server", $ns);
$this->nusoap_server->wsdl->schemaTargetNamespace = $ns;

//registrando funciones
$input_array = array ('a' => "xsd:string", 'b' => "xsd:string");
$return_array = array ("return" => "xsd:string");
$this->nusoap_server->register('addnumbers', $input_array, $return_array, "urn:SOAPServerWSDL", "urn:".$ns."/addnumbers", "rpc", "encoded", "Addition Of Two Numbers");
}

function index()
{
function addnumbers($a,$b)
{
$c = $a + $b;
return $c;
}

$this->nusoap_server->service(file_get_contents("php://input"));
}
}

Solamente tenemos dos métodos principales, el constructor y el index. En el constructor cargo mi biblioteca que a su vez llama a la nusoap, y configuro el servidor de nusoap. A continuación registro la función addnumbers (debajo del comentario “registrando funciones”). Ese grupo de código dice que la función recibe dos variables strings llamadas a y b, y que retorna otro string. Con $this->nusoap_server->register se registra la función especificando los parámetros de entrada y salida y un conjunto de parámetros que ahora no tienen importancia para este artículo. El último de ellos es un comentario o documentación del servicio addnumbers. Podrás ver que la función se implementa dentro del index, y después de esta función (y de todas las que adiciones) llamas a $this->nusoap_server->service.

Hasta aquí el servidor SOAP debe funcionar sin problemas. Podrás ver tus servicios publicados accediendo a tu sitio http://sitio/index.php/soapserver. Para consumir los mismos prepara otro controlador (por ejemplo soapserver_testing) y un método como este:

function test()
{
$params = array(
'a' => 2,
'b' => 3,
);

$result = $this->nusoap_client->call('addnumbers', $params);
}

Al cual accederías normalmente por el link http://sitio/index.php/soapserver_testing/test.

El problema que nos presenta SOAP sobre REST es que hay que declarar las variables de entrada y salida de cada función, y registrar cada función, lo cual es más pesado pero por supuesto genérico (recuerda que REST formatea cualquier resultado de BD directamente hacia un XML, JSON, etc. sin importar si los valores son enteros, cadenas, etc).

El gran problema con SOAP es a la hora de retornar consultas de la BD que implica la existencia de arreglos, objetos, tipos de datos complejos más allá de los string e int… para esto, debes construir la estructura de los objetos que retornarás. En el siguiente código te pongo un ejemplo completo, por pasos:

1. Creamos una clase que será el resultado del servicio. Utilizando la misma que creé para los servicios REST como te puse en la primera parte de este artículo, sería algo así (fuera de la clase Soapserver):

class Response_students
{
public $responseCode = 100;
public $responseMessage = 'Error desconocido';
public $data = NULL;
}

2. Declaramos un tipo de dato “Student” en el constructor de Soapserver (debajo del comentario “registrando funciones”):

$this->nusoap_server->wsdl->addComplexType(
"Student", //nombre del tipo de dato
"complexType", //tipo complejo
"struct", //en este caso struct por ser un objeto
"all", //no interesante ahora
"", //no interesante ahora
array( //miembros de la clase Student (columnas en la BD)
"NAME"=>array("name"=>"NAME", "type"=>"xsd:string"),
"AGE"=>array("name"=>"AGE", "type"=>"xsd:int")
)
);

3. Creamos un tipo de dato que será un arreglo de “Students”:

$this->nusoap_server->wsdl->addComplexType(
'Students_array',
'complexType',
'array', //tipo array porque es un arreglo de objetos
'',
'SOAP-ENC:Array', //estructura equivalente en SOAP
array(),
array(
array(
'ref' => 'SOAP-ENC:arrayType',
'wsdl:arrayType' => 'tns:Student[]' //contiene un array de Student
)
),
'tns:Student
);

4. Creamos el objeto respuesta de mi servicio, correspondiente a la clase Response_students del paso 1. La clase contiene un código que es un número, un mensaje string, y un objeto de tipo students_array creado en 3, que a su vez es un arreglo de Student creado en 2:

$this->nusoap_server->wsdl->addComplexType(
'Response_students',
'complexType',
'struct',
'all',
'',
array
('responseCode' => array('type' => 'xsd:int'),
'responseMessage' => array('type' => 'xsd:string'),
'data' => array('type' => 'tns: Students_array')
)
);

5. Registramos un método que va a devolver los estudiantes de un aula (class_room):

$this->nusoap_server->register(
"get_students", //nombre de la función
array('class_room' => "xsd:int"), //parámetros de entrada
array("return" => "tns: Response_students"), //objeto de salida
$ns,
$ns . "#get_students",
"rpc",
"encoded",
"Servicio que retorna los estudiantes de un aula"
);

6. Implementamos la función-servicio que retorna los estudiantes, dentro del index:

function get_students($class_room)
{
$CI = &get_instance();
$CI->load->model('students_model');
$students = $CI->students_model->get_students_of_room($class_room);

$result = new Response_students();

if (!empty($students))
{
$result->responseCode = 0;
$result->responseMessage = 'Estudiantes encontrados';
$result->data = array();
foreach ($students as $value)
$result->maintenances_data[] = $value;
}
return $result;
}

Listo. Recuerda que esto no es un tutorial, por eso no he explicado a profundidad todo el código. Basta con que te hayas llevado la idea de cómo es el funcionamiento de la biblioteca nusoap.

Espero que te hayan servido ambas partes del artículo, la relacionada con REST y esta con SOAP. Mi principal conclusión es que realmente hacen honor a los comentarios que te encuentras en internet: con REST implementas rápidamente cualquier servicio y él se encarga de formatearlo a XML u otras estructuras, pero es poco genérico; SOAP es más genérico pero es realmente complicado usarlo para estructuras complejas. De todas maneras, según el sistema que quieras implementar, las bibliotecas que te describí te pueden ser útiles para seguir incorporando funcionalidades a tus sitios implementados sobre CodeIgniter.

Referencias:

[1] SOAP Server In CodeIgniter using NuSOAP PHP Toolkit.htm

http://www.php-guru.in/2013/soap-server-in-codeigniter-using-nusoap-library/

[2] Descarga de biblioteca nusoap:

http://sourceforge.net/projects/nusoap/

{ Leer Más }


martes, 8 de octubre de 2013

Trabajando con Compact Framework 2.0 en el MC9090.

En este post les voy a mostrar una guía de cómo acceder a los servicios publicados en un sitio web mediante dispositivos móviles. Específicamente el dispositivo móvil MC9090 de Motorola, antes Symbol, que corre la versión 2.0 del Compact Framework de .Net y Windows CE (Compact Edition). Aunque este dispositivo lleva ya unos años en el mercado es ideal para entornos industriales como almacenes o pistas de combustibles. Gracias a las características que posee como: lector de códigos de barra, acceso a redes Wi-fi y diseño ergonómico. Además, por supuesto cuenta con la posibilidad de desarrollar aplicaciones personalizadas utilizando .Net.

Entonces nos ponemos en ello, vamos desarrollar una aplicación para este dispositivo que permita consumir los servicios publicados en una web y además utilizar su SDK para comunicarnos con el lector de códigos de barras.

Para nuestro ejemplo consumiremos un servicio de un sitio web publicado bajo la arquitectura RESTful. Les comento que REST (Representational State Transfer) es un estilo de arquitectura para la Web. Los servicios web basados en REST funcionan de manera similar al protocolo HTTP y utilizan los verbos (GET, POST, PUT, DELETE) para acceder a los recursos a través de una URL determinada. Por ejemplo, nuestro servicio utilizara como parámetro el código de barras leído en el dispositivo y de respuesta este devolverá un mensaje de notificación. Acá les muestro una URL de ejemplo para acceder al servicio pasándole el identificador ID5050 de un código de barras leído por el dispositivo:

http://localhost/rest_services/sample/bar_code/ID5050

En este caso se utiliza el verbo GET para acceder al servicio, es por ello que para cada código de barras capturado tendremos una URL diferente.

Antes de comenzar primero algunos detalles de nuestro entorno de desarrollo:

- Microsoft Visual Studio 2008: necesitamos específicamente esta versión porque aunque actualmente existen versiones más modernas de este magnífico IDE solo hasta esta versión nuestros amigos de Microsoft dieron soporte para el desarrollo en Smart Devices.

- EMDK de Motorola para .NET versión 2.8: esta es la SDK específica del proveedor para comunicarnos con las características especiales del dispositivo (ej. lector de código de barras). Incluye bibliotecas, herramientas, ejemplos y una excelente ayuda para facilitarnos nuestro trabajo. http://support.symbol.com/support/product/DEV_SW_TOOLS.html

Una vez que tenemos las herramientas instaladas en nuestra Pc estamos listo para comenzar. Primero creamos un nuevo proyecto de Smart Device en el Visual Studio:

clip_image002clip_image004

Aquí tenemos que cercioramos que seleccionamos la versión correcta de .Net Framework, en este caso 2.0. Luego en la siguiente ventana seleccionamos la plataforma de nuestro dispositivo móvil (Windows CE en nuestro caso), la versión del Compact Framework correspondiente y el tipo de aplicación, como queremos desarrollar una aplicación visual seleccionamos Device Application, y listo.

Primero vamos a acceder al lector de códigos de barras de nuestro equipo. Existen varias formas, aquí les explico la más sencilla e intuitiva con la cual podrán realizar la mayoría de las operaciones con el lector, pero si necesitan obtener más control del lector de código de barras pueden buscar en la ayuda de la EMDK. En este caso vamos a utilizar los DTC (Design Time Components) que nos proporciona la EMDK una vez instalada. Los DTC nos permitirá manejar la mayoría de las funcionalidades del lector de códigos de barras con un simple arrastrar y soltar desde nuestra Barra de Herramientas hacia nuestro formulario, análogo ha como lo hacemos con un botón o un combo box:

clip_image006clip_image008

Una vez con el componente insertado en nuestro formulario, podemos que configurar varias propiedades como los tipos de código de barras a leer y tipo de lector a utilizar. En la mayoría de los casos esta configuración podemos utilizarla por defecto así que en nuestro caso no la modificamos. Lo que si tenemos que hacer es adicionar el evento para manejar la captura del código de barras. Este DTC tiene 2 eventos asociados:

OnScan: Proporciona una notificación a la aplicación cada vez que se presiona el botón disparador del código de barras en el MC9090 y captura un código valido.

OnStatus: Proporciona una notificación a la aplicación cada vez que cambia el estado del lector de código de barras.

En nuestro caso añadimos un evento para cuando se capture el código de barras poder salvarlo y luego enviarlo a nuestro servicio web como parte de la URL:

clip_image010

Es importante tener en cuenta que para poder utilizar el lector de códigos de barras tenemos que habilitarlo en la aplicación como muestra la siguiente línea:

clip_image012

Igualmente justo antes de finalizar la aplicación tenemos que desabilitarlo para que este no cause problemas:

clip_image014

Ahora solo nos falta hacer uso del código de barras obtenido para consumir el servicio web. Si pudiéramos utilizar en este paso WCF (Windows Communication Foundation) prácticamente no tendríamos que hacer nada. Desafortunadamente WCF no está presente en la versión del Compact Framework 2.0 por lo que debemos realizar todo el trabajo por nosotros mismos. Esto se logra de la siguiente manera:

clip_image016

Aquí creamos un objeto de tipo HttpWebRequest, que es la clase de .NET que nos permite acceder a recursos webs a través del protocolo HTTP. Para esto necesitamos especificar la URL del servicio que deseamos consumir. El siguiente paso es especificar el método web que utilizaremos. Es importante aquí destacar como este es establecido mediante un string, siendo lo más lógico siguiendo el paradigma orientado a objeto, que existiera un Enum con todos los métodos web disponibles. Finalmente en la última línea el servicio es consumido y su respuesta almacenada en un objeto de tipo HttpWebResponse.

¿Pero, como accedemos a la información si esta se encuentra almacenada en un flujo de datos? Pues esto se logra de una manera bastante sencilla:

clip_image018

Como ven bastante sencillo. Aquí creamos un XmlReader pasándole el flujo de respuesta, luego obtenemos un XmlDocument a partir del XmlReader creado. En este punto el flujo de datos será transformado en un documento XML. Y voila, ya tenemos almacenado en el XmlDocument la respuesta del servicio, solo es cuestión ahora de pasearla en dependencia de lo que necesitemos leer. Para esto XmlDocument provee las utilidades necesarias. En WCF podríamos establecer mediante contratos el formato de los datos que recibiremos, pero como ya dijimos anteriormente aquí no contamos con esa posibilidad por lo que debemos conocer de antemano la naturaleza de estos. Hemos asumido que la respuesta viene en formato XML, para leer por ejemplo texto plano, como JSON, pueden hacer uso de la clase StreamReader.

Espero que le haya resultado útil el post, cualquier duda puede dejarnos un comentario.

{ Leer Más }


lunes, 23 de septiembre de 2013

Servicios web (webservices) con REST sobre CodeIgniter

PRIMERA PARTE

Acoplar bibliotecas para brindar servicios webs (webservices) sobre CodeIgniter, como en tantos otros casos, resulta extremadamente sencillo si has encontrado la biblioteca correcta. La complicación podría venir posteriormente cuando quieras utilizar las funcionalidades de la biblioteca utilizada. En este artículo te mostraré como utilizar dos tendencias: REST y SOAP, sobre CodeIgniter.

REST (Representational state transfer: transferencia representacional de estados), es un estilo que abstrae los elementos arquitectónicos en un sistema de hipermedia distribuido. REST ignora los detalles de implementación de los componentes y la sintaxis del protocolo, enfocándose en los roles de los componentes, su interpretación y la interacción con otros componentes. Ha emergido y es predominante como un API modelo de diseño web.

SOAP (Simple Object Access Protocol: protocolo de acceso a objetos) es un estándar que define cómo dos objetos en diferentes procesos pueden comunicarse por medio de intercambio de datos XML. Cuenta con buena extensibilidad, neutralidad (puede ser utilizado sobre cualquier protocolo de transporte como HTTP, SMTP, TCP o JMS) e independencia (permite cualquier modelo de programación).

Ambas tecnologías son buenas según tu objetivo. En internet se suele decir que REST es muy fácil de utilizar (por su abstracción) pero se recomienda para sistemas sencillos, en cambio SOAP es bastante difícil de utilizar (por ser tan genérica y flexible) y se recomienda para sistemas más complejos. Así que lo primero es definir qué modelo utilizarás según la complejidad de tu sistema.

En este artículo te mostraré ambas formas. Mi intención no es que entiendas perfectamente el funcionamiento de estas bibliotecas ni que aprendas a usarlas con solo leer este artículo. Solo quiere que te lleves la idea de la diferencia de complejidad en el uso de una u otra biblioteca, y que te sirva como punto de partida para buscar más información y brindar servicios web seguros y robustos. A la vez, demostrarte la facilidad con que ambas bibliotecas se integran con CodeIgniter.

REST

Para trabajar con REST en CodeIgniter te recomiendo descargar la biblioteca “CodeIgniter Rest Server” [2] (para PHP 5.2 o mayor y del CodeIgniter 2.1.0 al 3.0-dev). También puedes descargar el “CodeIgniter Rest Client” [3] si lo que deseas es consumir servicios. En mi caso solamente me interesa publicarlos.

Por cierto, si quieres consumir servicios con REST necesitas trabajar con cURL que te permite encapsular los datos que le pasas al servidor. Para esto puedes usar la biblioteca “CodeIgniter Curl library” [4].

Una vez descargada y descompactada la “CodeIgniter Rest Server”, notarás que es todo un proyecto de CodeIgniter con sus carpetas application y system. De esto solamente necesitas copiar “Format.php” y “REST_Controller.php” del application/libraries de la biblioteca para la carpeta application/libraries de tu sitio; y el fichero “rest.php” del application/config de la biblioteca para el application/config de tu sitio.

Luego adicionas un controlador con cualquier nombre, que herede de REST_Controller:

class Services_rest extends REST_Controller

Y listo, ya tienes acoplada la biblioteca a tu proyecto de CodeIgniter.

El segundo paso sería utilizar la biblioteca. Dado que puedes recibir peticiones por GET o por POST, la manera de que CodeIgniter Rest Server entienda cuál es la función adecuada es poniendo el sufijo get o post al final de las funciones. Por ejemplo el método students_get se ejecutará cuando se llame al servicio “students” vía GET, y el método students_post se ejecutará cuando se llame al servicio “students” vía POST. También existen los sufijos para PUT y DELETE.

En este link [1] podrás encontrar un tutorial muy completo de cómo acoplar CodeIgniter Rest Server a CodeIgniter, y te explica también cuándo y cómo usar PUT y DELETE, las ventajas y cómo usar cURL para consumir los servicios, etc.

Un ejemplo de una función-servicio con REST podría ser (dentro del controlador services_rest):

function students_get()
{
$result = new Response_students();

$id = $this->get('id');
$this->load->model('students_model');
$student = $this->students_model->get_student($id);

if (!empty($equipment))
{
$result->responseCode = 0;
$result->responseMessage = 'Equipo encontrado';
$result->student_data = $student;
}
else
{
$result->responseCode = 1;
$result->responseMessage = 'El estudiante no existe';
$result-> student_data = null;
}

$this->response($result, 200);
}

“Response_students” es una clase que creé para gestionar mejor los códigos y mensajes de errores, pero se puede retornar simplemente $this->response($student, 200) con los resultados sacados de una BD en forma de tabla, sin importar si es una fila o varias (por eso se destaca el nivel de abstracción de REST). El resultado se enviará al cliente sin problema alguno (el 200 es un código de respuesta, como 400, 404, etc).


Esta función como habrás notado se llamará vía GET y recibe un “id”. La forma de llamarla para comprobar sería:

http://sitio/services_rest/id/25 (sitio / controlador / nombre del parámetro / valor del parámetro, puedes ver en [1] una mejor explicación de esta sintaxis).

Puesto así se retorna una estructura XML que puedes ver directamente en tu navegador. Si lo quisieras en otro formato simplemente pondrías /format/el_formato, por ejemplo:

http://sitio/services_rest/id/25/format/json

Si la función fuera para ser utilizada por POST, capturarías el parámetro con $id = $this->post('id').

Con esto ya tienes montado tu servidor de webservices con REST y cada función es muy sencilla de implementar, con la facilidad de que REST traduce tus datos enviados por response a varios formatos de salida sin importar el tipo de dato proveniente de la BD (int, string…).

Faltaría prevenir que cualquiera teclee la dirección en la barra y acceda a tus datos o acceda al servicio sin autorización. Para esto entras a application/config/rest.php y pones:

$config['rest_auth'] = 'digest';   //línea 62
$config['rest_valid_logins'] = array(
'user1' => 'pass1',
'user2' => 'pass2'); //línea 109


Terminado. En la segunda parte de este artículo te hablaré entonces sobre el trabajo son la biblioteca nusoap sobre CodeIgniter.

Referencias:

[1] Working with RESTful Services in CodeIgniter,

http://net.tutsplus.com/tutorials/php/working-with-restful-services-in-codeigniter-2/

[2] Descarga de biblioteca CodeIgniter Rest Server:

http://github.com/philsturgeon/codeigniter-restserver

[3] Descarga de biblioteca CodeIgniter Rest Client:

http://github.com/philsturgeon/codeigniter-restclient

[4] Descarga de biblioteca CodeIgniter Curl library:

http://getsparks.org/packages/curl/show

{ Leer Más }


viernes, 20 de septiembre de 2013

¿Ingeniero de Software o Programador?

Hola comunidad. Decidí comenzar, con la pregunta que da título a este, una serie de artículos sobre ingeniería de software, programación y buenas prácticas en sentido general. A pesar del tiempo la interrogante sigue siendo polémica; fundamentalmente cuando nos estamos introduciendo en una especialidad tan amplia como la informática donde, muchas veces, desde cada posición se tiende a menospreciar la importancia del trabajo del otro.

clip_image002Y la pregunta en cuestión para mí sólo tiene una respuesta: AMBOS. No sólo porque son imprescindibles para desarrollar un software de calidad, sino porque, si somos capaces de conocer ambos desempeños seremos mucho mejores programadores e ingenieros de software.

En los inicios de lo que conocemos actualmente como industria del software, los primeros roles establecidos fueron el de analista y programador, en el intento de salir de la era del desarrollo de software “artesanal”. Estos roles aún existen por sus nombres, pero para aquel entonces sus competencias eran mucho más limitadas. El analista tenía como responsabilidad conocer paso a paso la actividad que se deseaba automatizar, la describía en papel detalladamente y era entonces que el programador, con sus conocimientos del lenguaje, las traducía a un programa. Dado que los problemas de comunicación entre estos roles eran considerables, la tendencia fue que el analista conociera de programación para manejar los mismos términos que el programador y que este, a su vez, conociera de la concepción de un programa para que no fuera sólo un traductor, sino un agente activo en la mejora del mismo. Ese proceso de interdisciplinariedad generó una expansión de ambos perfiles y tuvo como resultado el surgimiento de nuevos roles en la ingeniería de un proceso de desarrollo de software cada vez más depurado.

Actualmente, un programador tiene dominio de uno o más lenguajes y sus herramientas, que cada vez son más acabadas y complejas e incluyen definiciones arquitectónicas y patrones de diseño que, inevitablemente, llevan a que el programador esté cada vez más cerca del conocimiento integral del desarrollo de un sistema. Por lo que, si como programador tengo los conocimientos ingenieriles necesarios, se eleva mi rendimiento y obtengo como resultado calidad y eficiencia.

Por otro lado, desde mi punto de vista, un ingeniero de software sin experiencia de programación se verá muy limitado en el desempeño de los diferentes roles para los que supuestamente fue preparado. Pudiera enumerar un conjunto de situaciones frecuentes en las que se vería sumamente limitado su desempeño:

  1. ¿Cómo podría definir el flujo de un proceso a automatizar sin contar con un pensamiento orientado a objetos que dé un acabado al análisis del problema y sea el punto de partida al diseño?
  2. ¿Con qué base pudiera definirse la arquitectura de un sistema y tomar las decisiones arquitectónicas que se requieran en su desarrollo?
  3. ¿Cómo definir un diseño de clases correctamente y decidir que patrones quiero aplicar?
  4. ¿Cómo pudiera crear un diagrama UML de secuencias con las correspondientes llamadas entre clases sin saber que eso que está escribiendo “no compila”?
  5. ¿Cómo pudiera definir correctamente para un problema qué algoritmo utilizar y su complejidad?
  6. ¿Cómo definir correctamente pruebas de caja blanca?
  7. ¿Cómo liderar con efectividad un equipo de programadores sin saber qué es lo que hacen?

En general, salvo algunos roles que pudiera desempeñar con escasos o nulos conocimientos de programación, el ingeniero de software degenera a poco más que a ese primer analista que hablé existía en un principio, negando todos estos años de evolución del proceso de desarrollo de software, donde el ingeniero es quien lo hace posible.

{ Leer Más }


martes, 10 de septiembre de 2013

Desarrollando una lista de TO-DO usando base de datos y el Framework ZK.

clip_image002

Te mostraremos, paso a paso, como construir una sencilla aplicación web con ZK que use una base de datos. La aplicación web permitirá almacenar sucesos que vamos a hacer en el futuro o sea una lista de TO-DO. Una aplicación web así, requeriría usar una base de datos. Para la conclusión de este tutorial usaremos una base de datos Java (HSQL DB) la cual no requiere que instalemos un servidor de base de datos [1].

Pasos para ejecutar la aplicación:

  1. Descargue el código fuente de aquí.
  2. cd todo
  3. mvn jetty:run (si usted no tiene maven instalado por favor descárguelo aquí )
  4. Abra su navegador y coloque la siguiente url: http://localhost:8080/todo

clip_image003

Todos los Escenarios

§ Introduce toda la información relativa a un evento y presiona el botón  Add  para insertarlo en la base de datos.

§ Selecciona cualquier fila en la tabla para mostrar la información del evento en los campos de abajo para que modificar su información, después presiona el botón  Update  para modificar la información.

§ Selecciona cualquier fila en la tabla y presiona el botón  Delete  para eliminar el "Event" seleccionado.

Modelo

En los siguientes párrafos, el esquema de la base de datos, el objeto del dominio y el objeto DAO serán introducidos.

Esquema de la base de datos

Una tabla de la base de datos la cual va a almacenar los datos de nuestra aplicación, necesitará los siguientes atributos: event id, event name, event priority and event date.

El esquema de base de datos está listado abajo.

Field

Type

id

varchar(50)

name

varchar(50)

priority

int

date

date

Objeto Dominio

Para la la tabla de arriba, creamos el objeto de dominio correspondiente, como se indica:

public class TodoEvent {

private String id;

private String name;

private int priority;

private Date date;

public TodoEvent(String id, String name, int priority, Date date) {

this.id = id;

this.name = name;

this.priority = priority;

this.date = date;

}

// getter and setter methods are ommited, please refer to the source code.

}

Objeto de Acceso a Datos


Para que fácilmente se acceda a nuestra base de datos necesitaremos un objeto DAO con los siguientes métodos: findAll(),delete(),insert() and update().

public class EventDAO {

// The implementation is ommited, please refer to the source code.

public List<TodoEvent> findAll() {

}

public boolean delete(TodoEvent evt) {

}

public boolean insert(TodoEvent evt) {

}

public boolean update(TodoEvent evt) {

}

}

La Vista


Tu primer componente ZK


El primer paso es crear un fichero cuya extensión debe ser zul, pongamos todo.zul, y situamos este fichero bajo el directorio de nuestra aplicación web, por ejemplo, $TOMCAT_HOME/webapps/ProjectName/. Declaras un componente ZK de igual forma a como declaras un componente usando HTML.

Prueba a declarar tu primer componente  window  de la siguiente forma:

<window title="To do list" border="normal">

</window>

Después inicia Tomcat y usa el navegador para visitar la página, eg. http://localhost:8080/todo/todo.zul. El resultado se muestra abajo,  window  con el título 「To do List」.

Todo en ZK es un componente. Puedes cambiar el título, el alto y el borde de tu  window  Es muy sencillo e intuitivo. Intenta cambiar estos atributos y comprueba el resultado.

Relaciones jerárquicas entre los componentes de ZK


Lo siguiente, vamos a intentar enriquecer esta página con más componentes ZK. Para mostrar datos en una tabla, podemos usar un componente  listbox  el cual está diseñado para mostrar datos. Para insertar un listbox lo declaramos dentro de los tags del componente  window, como se indica:

<window title="To do list" border="normal">

<listbox id="box" multiple="true" rows="5">

</listbox>

</window>

En este ejemplo, el componente  listbox  es un componente hijo de  window. Sí, hay relaciones jerárquicas entre los componentes de ZK, te encontrarás una excepción UI si intentas declarar un componente dentro de un contexto equivocado, por ejemplo, al declarar un componente  window  como hijo de un componente  listbox.

Un componente anidado


Un listbox es un componente anidado, el cual soporta dos tipos de componentes hijos, listhead (aka: columna de la tabla), and listitem (aka: fila de la tabla). Con la declaración del  listbox, asignamos el atributo id a 「box」, ahora podemos usar este atributo para referenciar el listbox.

<window id="win" title="To do list" width="640px" border="normal">

<listbox id="box" multiple="true" rows="5">

<listhead>

</listhead>

<listitem>

</listitem>

</listbox>

</window>

Aún no hemos terminado. Vamos a declarar tres componentes listheader dentro de los tags de listhead. Necesitamos tres columnas -- 「Item」, 「Priority」, and 「Date」 -- dentro de la tabla, como se indica:

<window id="win" title="To do list" width="640px" border="normal">

<listbox id="box" multiple="true" rows="5">

<listhead>

<listheader label="Item" />

<listheader label="Priority" width="80px" />

<listheader label="Date" width="170px" />

</listhead>

<listitem>

</listitem>

</listbox>

</window>

Tenemos tres columnas en nuestra tabla, cada fila de la tabla también requerirá tres campos. Declaramos tres componentes listcell dentro de los tags del componente listitem.

<window id="win" title="To do list" width="640px" border="normal">

<listbox id="box" multiple="true" rows="5">

<listhead>

<listheader label="Item" />

<listheader label="Priority" width="80px" />

<listheader label="Date" width="170px" />

</listhead>

<listitem>

<listcell />

<listcell />

<listcell />

</listitem>

</listbox>

</window>

La estructura anidada del componente  listbox  quedaría así:

listbox 
+-- listhead
|    |
|    +-- listheader
|
+-- listitem
      |
     +-- listcell

Componentes para introducir información


En adición a mostrar estos eventos en el  listbox, necesitamos introducir información relativa al evento, incluyendo el evento name (campo texto), el evento priority (campo numérico) y el evento date (campo fecha). Para lograr esto, declare un textbox, un intbox y un datebox dentro de los tags del componente  window  de la siguiente forma:

<window id="win" title="To do list" width="640px" border="normal">

<listbox id="box" multiple="true" rows="5">

<listhead>

<listheader label="Item" />

<listheader label="Priority" width="80px" />

<listheader label="Date" width="170px" />

</listhead>

<listitem>

<listcell />

<listcell />

<listcell />

</listitem>

</listbox>

Item: <textbox id="name" cols="25" />

Priority: <intbox id="priority" cols="1" />

Date: <datebox id="date" cols="8" />

<button id="add" label="Add" />

<button id="update" label="Update" />

<button id="delete" label="Delete" />

</window>

 


Componentes Layout


Para distinguir los componentes de entrada de datos (input) de los componentes listbox de abajo, declaramos un groupbox para agrupar los componentes. Esto dibujará un borde alrededor de los componentes que estén contenidos dentro del groupbox, en este caso, los componentes de entrada de datos (input).

<window id="win" title="To do list" width="640px" border="normal">

<listbox id="box" multiple="true" rows="5">

<listhead>

<listheader label="Item" />

<listheader label="Priority" width="80px" />

<listheader label="Date" width="170px" />

</listhead>

<listitem>

<listcell />

<listcell />

<listcell />

</listitem>

</listbox>

<groupbox>

<caption label="Event" />

Item: <textbox id="name" cols="25" />

Priority: <intbox id="priority" cols="1" />

Date: <datebox id="date" cols="8" />

<button id="add" label="Add" />

<button id="update" label="Update" />

<button id="delete" label="Delete" />

</groupbox>

</window>

Adicionalmente a los componentes  groupbox  declaramos un componente  caption  para mostrar una etiqueta 「Event」 a lo largo de la caja que agrupa a los componentes. El componente caption trabaja de forma similar al legendario elemento en HTML.

Controlador


Nuestros requisitos incluyen mostrar, añadir, editar y borrar sucesos/eventos. En los siguientes párrafos, implementaremos las interacciones entre nuestra aplicación web y la base de datos.

Definiendo un Controlador


El primer paso es definir un EventController el cual herede de org.zkoss.zk.ui.util.GenericForwardComposer.

Implementando org.zkoss.zk.ui.util.GenericForwardComposer

Crea un EventController el cual heredará de org.zkoss.zk.ui.util.GenericForwardComposer permitiéndote un fácil acceso a la vista y definir un CRUD mediante los métodos Java definidos.

// org.zkforge.todo.event.EventController.java

public class EventController extends GenericForwardComposer {

private static final long serialVersionUID = -9145887024839938515L;

private EventDAO eventDao = new EventDAO();

// Note: Something is omitted at here. You can view detail about this class on source code.

public List<TodoEvent> getAllEvents() {

return eventDao.findAll();

}

public void onClick$add() {

}

public void onClick$update() {

}

public void onClick$delete() {

}

}

Asociando el Controlador con la Vista

Para implementar la interacción entre la Vista y el Controlador asignamos el atributo apply al componente window en la ruta de nuestro EventController.

<window id="win" title="To do list" width="640px" border="normal"

apply="org.zkforge.todo.event.EventController">

......

Visualizando datos en una Vista


Para visualizar los datos recuperados de la base de datos en nuestra Vista solo requerimos tres pasos:


  • Activar un mecanismo de DataBinding Mechanism
  • Asociar datos con la Vista
  • Definir una plantilla

Activando el mecanismo de DataBinding

Para usar el mecanismo Data Binding, deberemos activar el Data Binding Manager (org.zkoss.zkplus.databind.AnnotateDataBinderInit) en la parte superior de la página.

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>

<window id="win" title="To do list" width="640px" border="normal"

apply="org.zkforge.todo.event.EventController">

....

Asociando los datos con la vista

El paso siguiente es recuperar los datos de la base de datos mediante el EventController usando la expresión (win$composer.allEvents) para invocar EventController.getAllEvents(). El método EventController.getAllEvents() devuelve una lista que contiene todos los eventos almacenados en la base de datos que pueden ser asociados al atributo model del Listbox.

<window id="win" title="To do list" width="640px" border="normal"

apply="org.zkforge.todo.event.EventController">

<listbox id="box" multiple="true" rows="5" model="@{win$composer.allEvents}">

....

Puedes seguir los siguientes pasos para definir una plantilla de Interfaz de Usuario para renderizar los datos dentro de la vista.

Definiendo una plantilla

Es posible definir una plantilla de interfaz de usuario para renderizar DataBinding dentro de los correspondientes componentes de interfaz de usuario. Esto se logra gracias a la utilización de los atributos que ofrece el componente "listitem" definiendo una variable para representar cada instancia a reflejar.

<window id="win" title="To do list" width="640px" border="normal"

apply="org.zkforge.todo.event.EventController">

<listbox id="box" multiple="true" rows="5"

model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"

selectedItem="@{win$composer.current}">

<listhead>

<listheader label="Item" sort="auto(name)" />

<listheader label="Priority" width="80px" sort="auto(priority)" />

<listheader label="Date" width="170px" sort="auto(date)" />

</listhead>

<listitem self="@{each='event'}" value="@{event}">

<listcell label="@{event.name}" />

<listcell label="@{event.priority}" />

<listcell label="@{event.date}" />

</listitem>

</listbox>

Para más información, por favor dirígete a Associate UI Components with a Collection.

Sincronización de vistas


Una vez el usuario selecciona un ToDoEvent en el listbox, Necesitamos mostrarlo en el componente groupbox también. Sería mucho mejor si este tedioso trabajo fuera realizado de forma automáticamente. Data Binding es la respuesta! Simplemente asocia los datos con todo lo relacionado con los componentes de UI. El DataBinding se sincronizará entonces con todos los componentes de Interfaz de Usuario una vez la propiedad ha sido modificada.


  • Definir una instancia en un Controlador
  • Asociar múltiples componentes UI a la instancia

Definir una instancia "ToDoEvent" a un Controlador

Define una instancia ToDoEvent' en EventController, y define métodos getter y setter para que puedan ser accesibles desde la vista.

// org.zkforge.todo.event.EventController.java

public class EventController extends GenericForwardComposer {

private TodoEvent current = new TodoEvent();

// Omitted...

public TodoEvent getCurrent() {

return current;

}

public void setCurrent(TodoEvent current) {

this.current = current;

}

Asociando múltiples componentes UI con la instancia EventController

Primero, asocia la instancia EventController con la propiedad selectedItem del listbox. Después, asocia las propiedades del ToDoEvent con el correspondiente componente UI, incluyendo textbox, intbox, y datebox. Una vez el usuario selecciona un item en un listbox, la instancia se actualizará en relación a los componentes UI.

<listbox id="box" multiple="true" rows="5"

model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"

selectedItem="@{win$composer.current}">

<!-- Omitted -->

<groupbox>

<caption label="Event" />

Item: <textbox id="name" cols="25" value="@{win$composer.current.name}" />

Priority: <intbox id="priority" cols="1" value="@{win$composer.current.priority}" />

Date: <datebox id="date" cols="8" value="@{win$composer.current.date}" />

Sincronizando la vista con la base de datos


Además de mostrar los datos de la base de datos en la vista, nos gustaría implementar eventos para añadir, actualizar y eliminar. Esta funcionalidad requiere de tres pasos, monitorizar la actividad del usuario, interactuando con los controladores para actualizar la base de datos y actualizar la vista.


  • Registrar el evento Listener en el controlador
  • Actualizar la vista usando Databinding

Registrar el evento Listener en el Controlador

Para monitorizar la actividad del usuario, simplemente registramos un evento listener onClick' en los siguientes tres botones add, update and delete. Cuando cliqueamos en estos botones que se corresponden a los métodos definidos en EventController estos serán invocados. Estos métodos son definidos así:

public class EventController extends GenericForwardComposer {

private EventDAO eventDao = new EventDAO();

// Omitted...

public void onClick$add() {

if (current != null) {

current.setId(UUID.randomUUID().toString());

if (validate(current)) {

// insert into database

eventDao.insert(current);

}

}

}

public void onClick$update() {

if (current != null && validate(current)) {

// update database

eventDao.update(current);

}

}

public void onClick$delete() {

if (current != null && validate(current)) {

eventDao.delete(current);

}

}

}

<button id="add" label="Add" />

<button id="update" label="Update" />

<button id="delete" label="Delete" />


Actualizar la vista usando Databinding

Después de interactuar con la base de datos, el último paso es actualizar la vista. Simplemente notificar al Databinding para que actualice el modelo por ti, cuando el usuario cliqueé en cualquier botón. Intenta registrar un atributo load-after en el atributo model del listbox, y el Databinding actualizará la vista automáticamente si el evento especificado es capturado.

<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit"?>

<window id="win" title="To do list" width="640px" border="normal"

apply="org.zkforge.todo.event.EventController">

<listbox id="box" multiple="true" rows="5"

model="@{win$composer.allEvents, load-after='add.onClick, delete.onClick, update.onClick'}"

selectedItem="@{win$composer.current}">

<!-- Omitted... -->

<button id="add" label="Add" />

<button id="update" label="Update" />

<button id="delete" label="Delete" />

</groupbox>

</window>

Eso es todo, esperamos que le sea útil y quedamos al tanto de sus comentarios.




{ Leer Más }


IconIconIcon