Cómo ejecutar Talend 4.0 en Mac OS X

2.1.10. Por ooscarr (ooscarr)

La primera versión beta de Talend 4 (software comercial para ETL) tiene un pequeño error que impide que se ejecute a la primera en OS X.

Para una tarea de inteligencia de negocios nos pidieron usar Talend para el proceso de ETL y cuando fui a ejecutar el TalendOpenStudio-macosx-carbon.app de la versión de prueba de una temprana versión beta de Talend 4.0.0, aparecía el siguiente error:

The TalendOpenStudio-macosx-carbon executable launcher was unable to locale its companion launcher jar.

Para arreglarlo había que abrir el archivo TOS-All-r33789-V4.0.0M1/TalendOpenStudio-macosx-carbon.app/Contents/MacOS/TalendOpenStudio-macosx-carbon.ini. (Para abrir la .app, en el menú contextual sobre el archivo de la aplicación seleccionar Mostrar contenido del paquete).

Hay que editar la parte que dice

-startup
../../../plugins/org.eclipse.equinox.launcher_1.0.200.v20090520.jar

y reemplazarla por

-startup
../../../plugins/org.eclipse.equinox.launcher_1.0.201.R35x_v20090715.jar

Con eso, pude ejecutar la versión 4 (que ya viene con los permisos de ejecutables resueltos) con sólo hacer click en TalendOpenStudio-macosx-carbon.app en el dock.

Interfaz gráfica de Talend Open Studio 4.0.0M1 para Mac OS X.

Referencias

Etiquetas: ,

Saber el SID de Oracle en UNIX

12.12.09. Por ooscarr (ooscarr)

Estaba tratando de conectarme a Oracle desde SQL Developer pero el formulario de la conexión me pedía el SID. ¿Pero cuál es mi SID? ¿Ah?

Por suerte, Oracle estaba instalado sobre un ambiente parecido a UNIX como lo es Linux y pude conocer este dato entrando por SSH al servidor y escribiendo el comando:

echo $ORACLE_SID

Ventana de configuración de conexiones de SQL Developer para Mac OS X con el SID acinfo.

Para administrar mi base de datos estoy usando el software gratuito oficial de Oracle multi-plataforma SQL Developer (requiere registro previo en oracle.com).

Referencias

Etiquetas: ,

Columnas que se auto-incrementan en PostgreSQL

11.12.09. Por ooscarr (ooscarr)

PostgreSQL

MySQL tiene la posibilidad de crear columnas que se auto-incrementan en la misma definición de la columna a travé del comando AUTO_INCREMENT, no así PostgreSQL. En Postgres es más complicado, y de esta manera lo hago yo.

1. Crear secuencia

Con pgAdmin III

pgAdmin3 es una aplicación multi-plataforma que sirve para administrar las bases de datos PostgreSQL hecha por la misma comunidad PostgreSQL. Si l quieres hacer por líneas de comandos, avanza un poco más en este artículo.

Una vez abierto el pgAdmnin3 y hecha la conexión:

  1. Expando mi base datos, mi Esquema, elijo con el botón secundario del mouse la sección Secuencias y elijo en el menú contextual la opción Nueva Secuencia...

    Menú contextual sobre las Secuencias de una base de datos PotgreSQL en pgAdmin3.

  2. En el formulario le pongo un nombre (en mi caso se llamará transferencias_id), el usuario que hará uso de esta secuencia (en mi caso, el usurio se llama ooscarr) y OK. También puedo elegir si quier que se auto-incremente a partir de un número diferente al 1 y/o si quiero que el número vaya aumentando de 2 en 2, 3 en 3, etc. en vez de 1 en 1 como se pone por defecto.

    Diálogo de secuencia nueva en pgAdminIII. Si sólo se llenan los campos Nombre y Propietario, PostgreSQL los llenará automáticamente con incremento de 1 en 1, desde el número 1, y le asignará una OID, etc, etc.

Lo mismo, desde la línea de comandos

si seleccionas la nueva secuencia que se agrega a la lista puedes ver el comando SQL que se utilizó para crearla. Lo mismo se pudo haber hecho desde la línea de comandos psql con:

CREATE SEQUENCE transferencias_id;

ó

CREATE SEQUENCE transferencias_id
  INCREMENT 1
  MINVALUE 1
  START 1
  CACHE 1;
ALTER TABLE transferencias_id OWNER TO ooscarr;

transferencias_id es el nombre que le asigné a la secuencia y ooscarr es el usuario de PostgreSQL que es dueño de esta variable auto-incrementable.

2. Usar la secuencia en una columna

Con pgAdmin3

  1. Expandemos la tabla que queremos modificar, expandemos Columnas, y seleccionamos la columna de la tabla que se deseas que se auto-incremente con esta variable, vas a las Propiedades....
  2. En el inspector de columna, le asignamos el Valor por defecto NEXTVAL('transferencias_id'). Siendo transferencias_id el nombre de la secuencia.

    Diálogo de Propiedades de columna en pgAdminIII, con el campo Valor por defecto NEXTVAL('transferencias_id').

  3. OK

Con comandos (psql)

Sería...

ALTER TABLE transferencias 
    ALTER COLUMN id 
        SET DEFAULT NEXTVAL('transferencias_id');

transferencias_id es el nombre de la secuencia, id es el nombre de la columna a asignarle la secuencia y transferencias es el nombre de mi tabla donde está la columna con al secuencia.

Actualizar filas anteriores sin la secuencia

Con comandos

Para cambiar los valores null de las filas creadas antes de la asignación de la variable auto-incrementable, consultamos:

UPDATE transferencias 
    SET id = NEXTVAL('transferencias_id');

Ese paso final es una de las cosas más lentas que puedes pedirle a Postgres que haga posiblemente. Para una tabla de tamaño mediano (alrededor de 5,000,000 tuplas, con unas cuantas columnas de pequeños números y textos), eso tomó cerca de 2.5 horas en hardware poderoso - así que querrás dejar esto por un tiempo tranquilo. Afortunadamente Postgres interpreta el UPDATE como una transacción atómica: nada se realiza hasta que el comando se complete, así será difícil que dejes los datos en un estado inconsistente.

Y ya con eso, cada vez que crees una nueva fila en esa tabla, esa columna se llenará automáticamente con un número distinto automáticamente.

Referencias

Artículos relacionados

Etiquetas: , ,

Ejemplo de aplicación web con Hibernate que funciona usando Netbeans IDE y JSTL (JSP(X))

4.12.09. Por ooscarr (ooscarr)

Al final de este tutorial conocerás la dinámica del desarrollo de una aplicación web manejando la persistencia de la base de datos con Hibernate y cómo NetBeans IDE te ayuda a escribir el código y consultar la base de datos. También escribirás una aplicación web JSP que haga consultas a esta base de datos a través usando XML.

Este ejemplo de Hibernate es famoso, está documentado en varias páginas, pero todas tienen el código malo y es frustrante aprender así. Así que lo corregí y lo traduje al español sacando cosas de uno y de otro mismo tutorial que encontré en ¡chino, portugués, inglés y ruso!

Soporte para Hibernate en aplicaciones web está disponible desde NetBeans IDE 6.1. Desde NetBeans IDE 6.5, también puedes hacer ingeniería inversa a las tablas de una BD a archivos de mapeo y clases Java correspondientes usando un asistente intuitivo.

Pasos previos

Antes de empezar necesitarás:

  • Instalar NetBeans IDE. Al momento de escribir esto, anda dando vueltas la versión 6.8 RC2.
  • Instalar MySQL o Java DB, o tener acceso a conectarte a una de estas bases de datos con permiso para acceder o crear la base de datos Sakila. La base de datos Sakila está disponible en estos dos tipos de bases de datos, pero Hibernate funciona con cualquier JDBC, por ejemplo PostgreSQL y Oracle.
  • Importar la base de datos de ejemplo Sakila (a la que le haremos consultas en este ejemplo).

Una vez obtenido esto, asegúrate de configurar NetBeans IDE para poder acceder a la base de datos Sakila desde el panel "Prestaciones" (Menú Ventana > Prestaciones.

Instalar el complemento de Hibernate

El plug-in, si no lo tienes ya instalado, lo obtienes

  1. yendo, en el menú, a Herramientas > Complementos.
  2. En la ficha Plugins disponibles, selecciona la casilla del módulo Hibernate y presiona Instalar.

  3. Siguiente
  4. Acepta los términos de todos los contratos de licencia y presiona el botón de Instalar.
  5. Después que se descargue y se instale, presiona Terminar.
  6. Y listo, el módulo para Hibernate (o Hibernar) se activará solo; o sino, reinicia NetBeans IDE.

Crear Proyecto nuevo

Primero: lo típico. Creamos un Proyecto nuevo de tipo Aplicación web.

Asistente de Nuevo proyecto de NetBeans, bajo la categoría Web está la opción Aplicación web.

Para nuestro ejemplo, le damos el nombre DVDStore.

Elegimos un servidor como Tomcat o Glassfish, Siguiente y marcamos la opción Hibernate y seleccionamos la base de datos jdbc:mysql://localhost:3306/sakila, en nuestro caso, de la lista que, supongo, ya habías configurado anteriormente como indiqué en los pasos previos de este tutorial.

Asistente de Nuevo proyecto de NetBeans, después de marcar la casilla que habilita Hibernate 3.2.5 abajo selecciona la base de datos Sakila instalada en localhost.
Terminar

Fíjate que en:

  • DVDStore
    • Libraries

se agregaron automáticamente las librerías necesarias para utilizar Hibernate y conectar a la base de datos.

Configurar proyecto

hibernate.cfg.xml

Abre el archivo hibernate.cfg.xml que está en la ruta:

  • DVDStore
    • Source Packages
      • <paquete predeterminado>
        • hibernate.cfg.xml

Una vez abierto en NetBeans IDE, en el modo Diseño, en la parte Propiedades opcionales, Propiedades de configuración, pon Agregar... y añade la propiedad:

Nombre de la propiedad:hibernate.show_sql
Valor de la propiedad:true

Com el asistente de diseño de XML de configuración en NetBeans IDE se puede seleccionar los valores en una lista desplegable sin tocar el código XML.

Dentro de las mismas Propiedades opcionales del modo Diseño de NetBeans IDE, más abajo, en Propiedades varias, Agrega la propiedad:

Nombre de la propiedad:hibernate.current_session_context_class
Valor de la propiedad:thread

Después de esto, si ves el archivo hibernate.cfg.xml en el modo Operador XML, quedaría un código más o menos así, pero con otras contraseñas, por supuesto:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>
    <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/sakila</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">######</property>
    <property name="hibernate.current_session_context_class">thread</property>
    <property name="hibernate.show_sql">true</property>
  </session-factory>
</hibernate-configuration>

Guarda los cambios del archivo.

Asistente de ingeniería inversa de Hibernate

Agreguemos un nuevo archivo, y seleccionemos Hibernar > Asistente de ingeniería inversa de Hibernate

Asistente para la creación de nuevo archivo en NetBeans IDE. El primer paso es seleccionar la categoría Hibernar y luego, en la columna derecha, Asistente de ingeniería inversa de Hibernate

En el siguiente paso dejamos los valores por defecto (asegurándonos que pertenezca al proyecto DVDStore). Siguiente.

Se cargarán automáticamente los nombres de las tablas de la base de datos Sakila (elegida cuando creamos el proyecto), y seleccionaremos las tablas:

  • actor
  • category
  • film
  • film_actor
  • film_category
  • language

Asistente de ingeniería inversa de Hibernate tiene 2 columnas: Tablas disponibles (con las tablas en la base de datos) y Tablas seleccionadas (con las tablas que se utilizarán en el proyecto)
Para pasar tablas de una columnas a la otra, existen los botones Agregar > y < Eliminar.

Si marcas la casilla Incluir tablas relacionadas algunas otras tablas se incluirán automáticamente. Eso está bien.

Al presionar Terminar se va a crear un archivo hibernate.reveng.xml parecido a este:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
  <schema-selection match-catalog="sakila"/>
  <table-filter match-name="film"/>
  <table-filter match-name="language"/>
  <table-filter match-name="category"/>
  <table-filter match-name="actor"/>
  <table-filter match-name="film_category"/>
  <table-filter match-name="film_actor"/>
</hibernate-reverse-engineering>

No lo edites, cíerralo.

Archivos de mapas de Hibernate y POJOs de la base de datos

Crea un Archivo nuevo.... Categoría Hibernar, tipo Archivos de mapas de Hibernate y POJOs de la base de datos.

Asistente para la creación de nuevo archivo en NetBeans IDE. El primer paso es seleccionar la categoría Hibernar y luego, en la columna derecha, Archivos de mapas de Hibernate y POJOs de la base de datos.

Debes ponerle nombre a la clase donde estarán los mapas de Hibernate. Para que este tutorial funcione, ponle dvdrental

En el asistente de nuevo archivo de mapas de Hibernate y POJOs de la base de datos, en el paso de la Generación de código, debes seleccionar hibernate.cfg.xml como archivo de configuración de Hibernate e hibernate.reveng.xml como archivo de ingeniería inversa.

...y presiona el botón Terminar. Se deberían generar los siguientes archivos:

  • DVDStore
    • Source Packages
      • dvdrental
        • Actor.hbm.xml
        • Actor.java
        • Category.hbm.xml
        • Category.java
        • Film.hbm.xml
        • Film.java
        • FilmActor.hbm.xml
        • FilmActor.java
        • FilmActorId.java
        • FilmCategory.hbm.xml
        • FilmCategory.java
        • FilmCategoryId.java
        • Language.hbm.xml
        • Language.java

HibernateUtil.java

Lo último sería crear un Archivo Nuevo..., Categoría Hibernar, Tipo HibernateUtil.java.

Al crear el nuevo archivo HibernateUtil.java, en el asistente de nuevo archivo de NetBeans IDE, por favor fijarse en cambiar el nombre del archivo propuesto NewHibernateUtil por HibernateUtil sin el New y agregarlo al paquete dvdrental
Terminar

Empecemos

FilmHelper.java

Crea una nueva Clase Java (Archivo Nuevo..., Categoría Java, tipo Clase Java) y llámale FilmHelper y ponlo dentro del paquete dvdrental.

Creación de una nueva clase Java llamada FilmHelper en el paquete dvdrental utilizando NetBeans IDE 6.8 para Mac OS X.
Terminar

Agrega el siguiente código (en negrita) para crear una sesión de Hibernate.

package dvdrental;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

}

Van a aparecer unos errores que se arreglan usando el menú contextual (botón secundario del ratón) y eligiendo la opción Reparar importaciones.

Menú contextual aparece cuando uno hace click sobre el código fuente.
La opción Reparar importaciones en inglés se llama Fix import.

Si dejamos el valor por defecto, quedaría el código de FilmHelper.java de la siguiente manera:

package dvdrental;

import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }
 
}

Consultas HQL

Probemos algo. Haz click con el botón secundario sobre el archivo Source Packages/<paquete predeterminado>/hibernate.cfg.xml y selecciona la opción Ejecutar la consulta HQL del menú contextual.

Opción Ejecutar la consulta HQL aparece en el menú contextual sólo cuando se hace click sobre el archivo hibernate.cfg.xml.

En la barra de herramientas del editor de consultas HQL, selecciona la Sesión: hibernate.cfg y escribe lo siguiente en la primera caja de texto grande:

from Film

Y presiona el botón que está al lado de la lista desplegable que debería estar mostrando hibernate.cfg como opción seleccionada para hacer la consulta y obtener un resultado como el siguiente.

El Editor de consultas HQL de NetBeans IDE tiene dos partes: arriba para escribir la consultas y abajo para mostrar los resultados o equivalente SQL.

Ahora prueba con una consulta un poquito más complicada:

from Film as film where film.filmId between 100 and 200

Con las consultas probadas, obteniendo los resultados esperados, podemos utilizarlas en la clase helper.

Hibernate

Edita el archivo FilmHelper.java y agrégale el siguiente método (marcado con negrita):

package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }
 
  // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID

 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }
 
}

Repara las importaciones (Fix Import) si es necesario, utilizando las clases de hibernate.

Asistente para reparar importaciones en el código Java de NetBeans IDE. Instrucciones Import: Query org.hibernate.Query y List java.util.List.

para que quede completamente igual como está en el código de ejemplo anterior.

Vuelve a abrir el Editor de Consultas HQL y haz la siguiente query:

from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='10')

Esta consulta obtiene los actores de la película del filmid = 10.

Ahora súmale el siguiente método (marcado con negrita) al archivo FilmHelper.java:

package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

  // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID

 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }

 // Obtiene los actores en un film particular
 public List getActorsByID(int filmId) {
  List<Actor> actorList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='" + filmId + "')");
   actorList = (List<Actor>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return actorList;
 }

}

Repara las importaciones si es necesario. Guarda.

Ahora agrega 3 métodos más y algunos métodos que inventé para hacer uso de beans en el código JSPX.


package dvdrental;

import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;

public class FilmHelper {

 Session session = null;

 public FilmHelper() {
  this.session = HibernateUtil.getSessionFactory().getCurrentSession();
 }

 // Obtiene los films donde el id de film está entre un cierto rango especificado por las variables startID y endID
 public List getFilmTitles(int startID, int endID) {
  List<Film> filmList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId between '" + startID + "' and '" + endID + "'");
   filmList = (List<Film>) q.list();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return filmList;
 }

 // Obtiene los actores en un film particular
 public List getActorsByID(int filmId) {
  List<Actor> actorList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Actor as actor where actor.actorId in (select filmActor.actor.actorId from FilmActor as filmActor where filmActor.film.filmId='" + filmId + "')");
   actorList = (List<Actor>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return actorList;
 }

 // Obtiene una lista de categorías de acuerdo al filmId
 public Category getCategoryByID(int filmId) {
  List<Category> categoryList = null;
  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Category as category where category.categoryId in (select filmCat.category.categoryId from FilmCategory as filmCat where filmCat.film.filmId='" + filmId + "')");
   categoryList = (List<Category>) q.list();

  } catch (Exception e) {
   e.printStackTrace();
  }

  return categoryList.get(0);
 }

 // Obtiene un solo film de acuerdo al filmId
 public Film getFilmByID(int filmId) {

  Film film = null;

  try {
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Film as film where film.filmId=" + filmId);
   film = (Film) q.uniqueResult();
  } catch (Exception e) {
   e.printStackTrace();
  }

  return film;
 }


 // Obtiene el idioma del film de acuerdo a un langId
 public String getLangByID(int langId) {

  Language language = null;

  try{
   org.hibernate.Transaction tx = session.beginTransaction();
   Query q = session.createQuery("from Language as lang where lang.languageId=" + langId);
   language = (Language) q.uniqueResult();
  } catch (Exception e) {
   e.printStackTrace();
  }

  return language.getName();
 }



 //Métodos para no poner código java en el JSPX
 int startId;
 int endId;

 int filmId;
 int langId;

 public void setAttributeStartID(int startId){
  this.startId = startId;
 }
 public void setAttributeEndID(int endId){
  this.endId = endId;
 }
 public List getFilmTitlesList(){
  return getFilmTitles(startId,endId);
 }
 public void setAttributeFilmByID(int filmId){
  this.filmId = filmId;
 }
 public List getActorsID() {
  return getActorsByID(filmId);
 }
 public Category getCategoryID() {
  return getCategoryByID(filmId);
 }
 public Film getFilmID() {
  return getFilmByID(filmId);
 }
 public void setAttributeLangByID(int langId){
  this.langId = langId;
 }
 public String getLangID() {
  return getLangByID(langId);
 }

}

JSP(X)

Hurra. Por fin llegamos a las páginas web. A mi me gusta escribir las JSP con JSTL así que antes de seguir deberás...

Instalar la librería JSTL

  1. Entra a las propiedades del proyecto (botón secundario del ratón sobre DVDStore, opción Propiedades).

  2. En la sección Libraries hay un botón Add Library.... Presiónalo.
  3. Si no te aparece inmediatamente, Importa la librería (o biblioteca también le llaman) JSTL 1.1 o superior.
  4. Selecciona la librería JSTL y añádela al proyecto.
  5. Aceptar

Nuevo archivo JSPX

Primero elimina el archivo index.jsp del proyecto que está en la carpeta DVDStore/Web Pages/ del proyecto.

Agrega un nuevo archivo JSPX y cambia la página por defecto.

En el archivo index.jspx escribe lo siguiente.

index.jspx
<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    Document   : index
    Created on : 01-dic-2009, 21:43:16
    Author     : ooscarr
-->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
     xmlns:c="http://java.sun.com/jsp/jstl/core"
     xmlns:fn="http://java.sun.com/jsp/jstl/functions">

 <jsp:output
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  doctype-root-element="html"/>

 <jsp:directive.page import="dvdrental.*"/>
 <jsp:directive.page import="java.util.List"/>

 <jsp:directive.page contentType="text/html" pageEncoding="UTF-8"/>

 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <title>DVDStore</title>
  </head>
  <body>


   <c:set var="startID" value="1"/>
   <c:set var="endID" value="10"/>
   <c:set var="prev_startID" value="1"/>
   <c:set var="prev_endID" value="10"/>
   
   <c:set var="FILM_RECORD_COUNT" value="1000"/>
   
   <c:set var="RECORD_START_PAGE" value="false"/>
   <c:set var="RECORD_END_PAGE" value="false"/>


   <c:if test="${not empty param.startid}">
    <c:set var="startID" value="${param.startid}"/>
   </c:if>
   <c:if test="${not empty param.endid}">
    <c:set var="endID" value="${param.endid}"/>
   </c:if>

   <jsp:useBean id="helper" class="dvdrental.FilmHelper"/>
   <!-- Invento para pasar filmID a FilmHelper.java -->
   <c:set target="${helper}" property="attributeStartID" value="${startID}"/>
   <c:set target="${helper}" property="attributeEndID" value="${endID}"/>
   <c:set var="filmTitles" value="${helper.filmTitlesList}"/>

   <c:if test="${startID == 1}">
    <c:set var="RECORD_START_PAGE" value="true"/>
   </c:if>
   <c:if test="${endID == FILM_RECORD_COUNT}">
    <c:set var="RECORD_END_PAGE" value="true"/>
   </c:if>

   <c:set var="prev_startID" value="${startID-10}"/>
   <c:set var="prev_endID" value="${endID-10}"/>

   <c:set var="startID" value="${endID+1}"/>
   <c:set var="endID" value="${endID+10}"/>

   <c:set var="filmTitlesSize" value="${fn:length(filmTitles)}"/>


   <table>
    <thead>

     <c:choose>
      <c:when test="${RECORD_START_PAGE}">
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${startID}&amp;endid=${endID}">Next</a></td>
       </tr>
      </c:when>
      <c:when test="${RECORD_END_PAGE}">
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${prev_startID}&amp;endid=${prev_endID}">Prev</a></td>
        <td class="NEXT"> </td>
       </tr>
      </c:when>
      <c:otherwise>
       <tr>
        <td class="NEXT"> </td>
        <td class="NEXT"> </td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${prev_startID}&amp;endid=${prev_endID}">Prev</a></td>
        <td class="NEXT">
         <a class="NEXT" href="index.jspx?startid=${startID}&amp;endid=${endID}">Next</a>
        </td>
       </tr>
      </c:otherwise>
     </c:choose>


     <tr><th>Title</th><th>Description</th><th> </th><th> </th></tr>
    </thead>
    <tbody>

     <c:forEach items="${filmTitles}" var="i">
      <c:set var="film" value="${i}"/>
      <c:set var="filmID" value="${film.filmId}"/>
      <tr>
       <td class="COL1">
        <a href="browse.jspx?id=${filmID}">${film.title}</a>
       </td>
       <td class="COL2">${film.description}</td>
       <td class="COL2">
        <a href="browse.jspx?id=${filmID}">More</a>
       </td>
       <td class="COL2">
        <a href="rent.jsp?id=${filmID}">Rent</a>
       </td>
      </tr>
     </c:forEach>

    </tbody>
   </table>

  </body>
 </html>
</jsp:root>

Ya lo puedes hacer correr si quieres probarlo.

Si no te gusta escribir las JSP con JSTL, puedes revisar el código oficial donde está lo mismo pero en clave Java clásico.

browse.jspx

Crea otro archivo JSP con sintaxis XML que se llame browse con el siguiente código:

<?xml version="1.0" encoding="UTF-8"?>
<!-- 
    Document   : browse
    Created on : 29-nov-2009, 19:47:16
    Author     : ooscarr
-->
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"
     xmlns:c="http://java.sun.com/jsp/jstl/core">

 <jsp:output
  omit-xml-declaration="no"
  doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
  doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
  doctype-root-element="html"/>

 <jsp:directive.page import="dvdrental.*"/>
 <jsp:directive.page import="java.util.List"/>

 <jsp:directive.page contentType="text/html" pageEncoding="UTF-8"/>

 <html xmlns="http://www.w3.org/1999/xhtml">
  <head>
   <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
   <title>DVDStore browse</title>
  </head>
  <body>
   
   <!-- Get title ID -->
   <c:set var="filmID" value="1"/>
   <c:if test="${not empty param.id}">
    <c:set var="filmID" value="${param.id}"/>
   </c:if>

   <c:set var="startPage">false</c:set>
   <c:set var="endPage">false</c:set>

   <jsp:useBean id="helper" class="dvdrental.FilmHelper"/>

   <!-- Invento para pasar filmID a FilmHelper.java -->
   <c:set target="${helper}" property="attributeFilmByID" value="${filmID}"/>

   <jsp:useBean id="film" class="dvdrental.Film"/>
   <c:set var="film" value="${helper.filmID}"/>

   <c:set var="filmTitle" value="${film.title}"/>
   <c:set var="filmDescription" value="${film.description}"/>

   <!-- Get Actors -->
   <c:set var="actors" value="${helper.actorsID}"/>

   <!-- Get Category -->
   <c:set var="category" value="${helper.categoryID}"/>

   <c:set var="totalCast">
    <c:forEach items="${actors}" var="i">${i.firstName} ${i.lastName}, </c:forEach>
   </c:set>

   <!-- Invento para pasar langId a FilmHelper.java -->
   <c:set target="${helper}" property="attributeLangByID" value="${film.languageByLanguageId.languageId}"/>
   <!-- Obtiene el idioma usando el langId entregado anteriormente -->
   <c:set var="language" value="${helper.langID}"/>
   
   <c:set var="filmLength" value="${film.length}"/>
   <c:set var="filmRating" value="${film.rating}"/>
   <c:set var="filmYear" value="${film.releaseYear}"/>
   
   <c:set var="rentalDuration" value="${film.rentalDuration}"/>
   <c:set var="rentalRate" value="${film.rentalRate}"/>

   <c:set var="specialFeatures" value="${film.specialFeatures}"/>


   <table>
    <tr>
     <td class="RENT"> </td>
     <td class="RENT">
      <a class="RENT" href="browse.jspx?id=${filmID}">Arrendar</a>
     </td>
    </tr>
    <tr>
     <th class="TITLE">Título</th>
     <td class="TITLE">${filmTitle}</td>
    </tr>
    <tr>
     <th class="COL1">Descripción</th>
     <td class="COL2">${filmDescription}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Género</th>
     <td class="COL2">${catName}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Reparto</th>
     <td class="COL2">${totalCast}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Duración de la película</th>
     <td class="COL2">${filmLength} <abbr title="minutos">mins.</abbr></td>
    </tr>
    <tr>
     <th class="COL1">Idioma</th>
     <td class="COL2">${language}</td>
    </tr>
    <tr>
     <th class="COL1">Calificación cinematográfica</th>
     <td class="COL2">${filmRating}</td>
    </tr>
    <tr>
     <th class="COL1">Año</th>
     <td class="COL2">${filmYear}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Características especiales</th>
     <td class="SPECIAL">${specialFeatures}</td>
    </tr>
    <tr>
     <td class="COL1"> </td>
     <td class="COL2"> </td>
    </tr>
    <tr>
     <th class="COL1">Precio Arriendo</th>
     <td class="COL2">US$ ${rentalRate}</td>
    </tr>
    <tr>
     <th class="COL1">Duración de Arriendo</th>
     <td class="COL2">${rentalDuration} días</td>
    </tr>
   </table>

   </body>
 </html>
</jsp:root>

Ejecuta la aplicación en el servidor, visita la página (en mi máquina se está ejecutando en http://localhost:8084/DVDStore/) y Voilà!. Funciona o te equivocaste.

Conclusiones

A pesar de que este ejemplo sólo hace lecturas a la base de datos, me puedo imaginar que escribir debe ser igual de sencillo ya que autmáticamente se generan la clases bean para insertar valores (set).

Con la persistencia ya no me tengo que preocupar de hacer la conexión y desconexión en cada página, la contraseña está guardada de manera más segura y estandarizada, y el acceso a las tablas se hace sencillo manejándolas como clases (un editor de Java ayuda a completar el código) y no andan las consultas SQL dando vueltas por todo el código, lo que ofrece mayor abstracción entre los distintos niveles del código otorgando flexibilidad a cambios.

Si se me ocurre cambiar la base de datos (agregar una columna, modificar el nombre de una tabla o las relaciones y tipos de datos), habría que regenerar los mapas de Hibernate y volver a compilar todo.

También, si nos fijamos en todo lo que hay que saber sobre programación Java, se hace más difícil la programación, aunque supongo y reconozco que con el tiempo se debe volver más sencillo con la experiencia. Obvio.

Mejoras en el rendimiento... No sé. Supongo que al tener todas las consultas guardadas... Y con Hibernate preocupado de las conexiones y desconexiones... Me imagino que sí hay alguna mejora, lo desconozco.

En el próximo capítulo...

Esto fue cómo leer desde una base de datos con Hibernate, prometo escribir sobre cómo escribir en la base de datos usando Hibernate y hacer este mismo ejemplo usando JPA, que ya lo tengo hecho, pero hay que desarrollarlo y darle formato. Hasta el próximo mes.

Referencias

Artículos relacionados

Etiquetas: , , , ,

El Modelo OSI y el error de capa 8 ¬¬

29.11.09. Por ooscarr (ooscarr)

Sería bueno explicar qué significa el chistecito del error de capa 8 para los incautos. Lo sospechaba. Aprovecho aquí también de conocer los otros 7 niveles.

El chistecito del error de capa 8 viene del Modelo OSI, que de acuerdo a Wikipedia:

El modelo de referencia de Interconexión de Sistemas Abiertos (OSI, Open System Interconnection) fue el modelo de red descriptivo creado por la Organización Internacional para la Estandarización lanzado en 1984. Es decir, fue un marco de referencia para la definición de arquitecturas de interconexión de sistemas de comunicaciones.

7 capas del modelo OSI

Este modelo presenta 7 capas:

Pirámide que enumera las 7 capas del modelo OSI con el Nivel Físico (Capa 1) como base y el Nivel de Aplicación (Capa 7) en la parte superior.

Capa 1: Capa Física
Se refiere al medio físico de transporte como los cables o las ondas, por ejemplo. O también en el proceso de codificar la información para adaptarla al medio físico en que se transportará.
Capa 2: Capa de enlace de datos
La capa de enlace de datos se ocupa del direccionamiento físico, de la topología de la red, del acceso a la red, de la notificación de errores, de la distribución ordenada de tramas y del control del flujo.
Capa 3: Capa de red
Los enrutadores o routers y/o la saturación de la red o paquete.
Capa 4: Capa de transporte
Es cuando se dividen la información en paquetes para ser transportados por la Capa 3, la que se encarga de la comunicación independientemente del medio de transporte de la información.
Capa 5: Capa de sesión
Esta capa es la que se encarga de mantener y controlar el diálogo establecido entre los dos computadores que estan transmitiendo datos de cualquier índole.
Capa 6: Capa de presentación
El objetivo de la capa de presentación es encargarse de la representación de la información, de manera que aunque distintos equipos puedan tener diferentes representaciones internas de caracteres (ASCII, Unicode, EBCDIC), números (little-endian tipo Intel, big-endian tipo Motorola), sonido o imágenes, los datos lleguen de manera reconocible.
Capa 7: Capa de aplicación
Son los protocolos de comunicación como HTTP, SSH, POP, etc. Cabe aclarar que el usuario normalmente no interactúa directamente con el nivel de aplicación. Suele interactuar con programas que a su vez interactúan con el nivel de aplicación pero ocultando la complejidad subyacente.

Error de capa 8 y capa 9

La capa 8 es un chiste usado para referiste a una capa "usuario" o "política" inexistente. Error Capa 8: Error del Usuario. También es conocido como el "error 505" entre el teclado y el asiento. O sea, tú.

"Error Capa 9: Error del Jefe del Usuario" XD

Nerd.

Referencias

Etiquetas: ,

Publicidad