Pedro del Gallego's Weblog
lunes noviembre 01, 2004
JUnit, NUnit y TestNG EL problema :
Hoy he tenido una mañana de perros, uno de esos dias en lo que te pones a tirar lineas de código sin mucho esfuerzo, pero cuando llega la hora del crear los test, estos como por arte de mágia se niengan a funcionar.
El caso es que estaba yo haciendo mi pequeña práctica para ingenieria del software II, bastante sencilla, cuando decido crear unos test con JUnit ... de repente el código no funciona ... lo reviso y joder el código estoy seguro de que tiene que funcionar, el error esta en una clase de no mas de 50 lineas...vuelvo al test... vuelvo al código... otro test... vuelvo al código... otro test... vuelvo al código....otro test...vuelvo al código...SOCORRO GOOOOGLE!!
Despues de un buen rato dando vueltas por la página de JUnit.. decido probar suerte con los demas enlaces... y llego a este post del señor Flower, a traves del blog de Cedric (El cual no leia pero que veo que tiene un monton de post y proyectos interesantes, entre ellos TestNG)
La causa :
El problema no estaba en mi código (ufff me estaba volviendo loco), sino en como entendia yo que funcionaba JUnit. Resulta que JUnit hace una instancia de nuestra clase sobre por cada metodo que vayamos a probar. En el código que pone Flower queda muy clarito.
El efecto :
Esto me ha hecho curiosar con otros dos framework de pruebas
- NUnit : Esta framework es un porte de JUnit a C#, sigue las mismas bases, pero con algunas diferencias, escribiendo mi clase en C# esta pasaba el test perfectamente :)
- TestNG : Este si tiene bastantes diferencias con respecto a JUnit, viendo el tutorial lo pirmero que me llama la atencion es el hecho que podemos usar anotaciones (segun el JSR 175) para introducir informacion sobre las clases y metodos que vamos a testear.
Para experimentar un poco he decidido pasar mis practicas a C# asi que en un proximo post os dare mis impresiones sobre este. ¿Habeis probado alguno de estos frameworks en vuestros poryectos?
( nov 01 2004, 12:38:38 PM CET )
Permalink
lunes octubre 18, 2004
Slides monografico JDK 5.0 pues eso
aqui dejo las Slides para obtener un poco de feedback
( oct 18 2004, 11:06:41 PM CEST )
Permalink
jueves octubre 14, 2004
Anotaciones.
Preparando el monografico de JDK 5.0 he descubierto una caracteristica que me ha llamado la atencion por encima de las demas:
las anotaciones.
Con as anotaciones podemos incluir datos sobre nuestro código (meta-datos, para ser mas exactos, incluso meta-meta-datos o meta-meta-meta-...-metadatos, aunque esto lo dejo para proximos post.)
Estas anotaciones no son simples "code-generators" tipo XDoclet, sino que pueden contener informacion para el compilador para la máquina virtual sobre como manejar ese codigo. Tambien se pueden usar para indicar parametros a un contenedor,... y para que mas pueden servir las anotaciones, pues para un monton de ideas locas, pero en lo primero que pense (sobre todo leyendo algunos los ejemplos) es que pronto apareceran muchos proyectos OS que nos indicaran el estado de nuesto código basandose en anotaciones tipo
TODO, INPROGRESS, DEPRECATED...
Lo importante, es que podemos crear nuestras propias anotaciones (que enprincipio son solo un conjunto muy limitado). Esto inevitablemete nos llevara a que Apache o Sun, creen un JSAL (Java Standard Annotations Library ;)... yo por el momento estoy intentando desarrollar una pequeña libreria de pruebas. con las siguientes anaotaciones:
- @NotNull : Una etiqueta que indique que un parametro no puede ser nulo, seria una buena forma de de empezar a tener mas en cuenta el "diseño basado en contrato", esta genial etiqueta no es nueva, y C# tiene algo parecido.
- @pre : Contendria un conjunto regla de asserciones que se deben cumplir antes de ejecutar un metodo
- @post : Contendria un conjunto regla de asserciones que se deben cumplir despues de ejecutar un metodo
- @Validate : Una etiqueta que el parametro debe ser parametro debe ser validado por el metodo X.xxx()
class Example {
void insert(@NonNull List list,
@validate(methodValidate="validate.email", exception = "org.akuma.exception.mailValidationException") String email) {
// code can assume list and o are each not null,
// because an exception will be thrown if they are null
}
@NonNull(menssage="method can´t return null") String getSomething() {
// code cannot return null, or exception and/or
// compile time error occurs
}
}
Ejemplo de etiqueta :
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Documented;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target ({ElementType.PARAMETER})
public @interface NonNull {
String exception() default "java.lang.Exception";
String menssage() default "Parameter can´t be null";
}
Por ahora no se muy bien como modificar el codigo en ejecucion, supongo que a lo bruto podría usar BCEL o algo asi... ya veremos, a ver si hacen los dias un poco mas largos, que no nos da tiempo a hacer todo lo que queremos
( oct 14 2004, 03:53:15 PM CEST )
Permalink
jueves septiembre 30, 2004
regexp y Tiger Bueno yo sigo con mi monologo del tigre (por ahora no me aburro del juguete nuevo)
He descubierto un ejemplo muy gracioso que combina las nuevas caracteristicas de la API java.util.regex junto con generics y el nuevo loop.
import java.util.regex.*;
import java.util.*;
public class FindAll {
public static void main(String[] args) {
Pattern pattern = Pattern.compile(args[0]);
String text = args[1];
List results = findAll(pattern, text);
for(MatchResult r : results) {
System.out.printf("Found '%s' at (%d,%d)%n",
r.group(), r.start(), r.end());
}
}
public static List findAll(Pattern pattern, CharSequence text)
{
List results = new ArrayList();
Matcher m = pattern.matcher(text);
while(m.find())
results.add(m.toMatchResult());
return results;
}
}
PS : Ejemplo robado sin piedad ni misericordia al señor
Flanagan, que seguro que no e queja de que mandemos gente a su blog y vean que tiene un libro sobre el tema.
( sep 30 2004, 06:22:32 PM CEST )
Permalink
lunes septiembre 27, 2004
Terminologia : Tipos de objetos [nota]YA me canse de describir siempre lo mismo en multiples articulos, transparencias, etc, asi que a partir de ahora esta sera una de mis paginas para referenciar y no tener que escribir 10 veces lo mismo. Lo ideal es que esto fuera un wiki, que estuviese en jH y que fuese colaborativo. Pero estoy un poco vago, y como no quiero crear un proyecto y luego dejarlo a la mano de dios pues lo hago aqui, eso si si alguien se ve con ganas de hacerlo que cuente con mi apoyo. [/nota duracion="Esta nota se autodestruira en la proxima actualización"]
Object / Instance/ Class
Un objeto tal y como lo describe The Java Language Specification.
Un instancia tal y como lo describe The Java Language Specification.
Un clase tal y como lo describe The Java Language Specification.
POJO (Plain Old Java Object)
Es un objeto que no implementaa ningun tipo de especificacion de componentes, bean o cilco de vida.
Es un acronimo de Plain Old Java Object
Javabean / Bean
Un objeto es un java bean valido si esta bien formado con respecto a la especificacion JavaBean. Esto es si el objeto tienen constructor publico por defecto y soporta la modificación y/o la recuperacion totalmente o en parte de su estado mediante llamadas a metodos setter y getter (getXXX(), setXXX() o isXXX(), donde Xxx identifica un aspecto de su estado.) Pueden represnetar tanto datos como funcionalidades.
Data Object / Entity Bean / Data Bean / PODO
Objetos que solo representan datos y que no contienen ninguna lógica de negocio. En ocasiones se sobre escribiben los metodos equals() y hashCode() otras se hacen serializable o XmlSerializables. No crean hilos, no contienen referencias a objetos que no sean de datos.
Entity Beans?
Session Statefull Beans?
Session Stateless Beans?
Message-Driven Beans?
( sep 27 2004, 12:32:37 PM CEST )
Permalink
domingo septiembre 26, 2004
Antipatron : Concrete Class Dependency O el "Antipatrón" mas sencillo del mundo.
Estaba yo revisando un código antiguo, es decir refactorizando modernamente ;), cuando vi la peculiar forma que tenia de hacer las cosas y es que, como todos, mi forma de tirar código va variando segun los conocimientos (y modas) pero sobre todo segun los trompazos que
me vaya dadon contra mis propios ladrillos de código, una de las cosas que mas rápido se aprende en la POO, es que cuanto menos dependas de algo mejor (otra cosa, es que lo pongamos en práctica pronto)
Pues bueno a lo que voy, para desacoplar una clase que depende de otra debemos seguir la maxima Interface Implementation Separation (apartir de ahora IIS, ummm mejor no ;). Veamos esto en código.
Antipatron : Concrete Class Dependency
public class A {
private final B b;
public A(B b) {
this.b = b;
}
}
public class B {
}
Como vemos A depende de una instancia concreta de B, con lo facil que seria esto:
Solución
public interface B {
}
public class BImpl implements B {
}
Con Esto reduciremos el grado de acoplamiento que existen entre la clase A con respecto de la B. Espero que esto le sirva a alguien para que no tenga que esconder código debajo de la manta como yo :P .
PS I: Ejemp tomado de la página de picocontainer.
( sep 26 2004, 06:04:00 PM CEST )
Permalink
viernes septiembre 10, 2004
El trigre : Cosas que me gustan y cosas que no Preparando un monografico sobre Java 1.5, me he dado cuenta de que varias cosas de este caracteristicas del lenguaje no me agradan.
- Generics : Esta novedad me encanta, sencillez, limpieza y chequeo en tiempo de compilacion un ejemplo simple :
static void expurgate(Collection *String* c) {
for (Iterator *String* i = c.iterator(); i.hasNext(); )
if (i.next().length() == 4)
i.remove();
}
Donde aparecen los asteriscos deberian ir los signos de mayor y menor
- Enhanced for Loop : Esta caracteristica me produce una sensacion ambigua, me gustan los nuevos bucles son mas limpios, mas cortos, mas compresibles, pero reelamente no añaden nada extra al lenguaje
for(Object word : wordlist) {
System.out.print((String)word + " ");
}
- Autoboxing/Unboxing : Esta no me gusta mucho, para que me sirve esto, para ahorrarme una serie de castings. Creo que el marcar expicitamente el casting se autodocumentaba mas el codigo y no era algo demasiado tedioso.
- Typesafe Enums : Esto simplemente es algo que llevavamos echando de menos hace bastante tiempo. Ya era hora !! :-@
- Static Import : Otra de esas cosas que no se muy bien para que lo meten. Puede que evite en cierto modo "constant interface" dicese de esto (yo tampoco sabia que tenia este nombre :P
public interface Physics {
public static final double AVOGADROS_NUMBER = 6.02214199e23;
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
public static final double ELECTRON_MASS = 9.10938188e-31;
}
Pero tampoco me parece una gran solucion. no se tendre que echarle un ojo mas detenidamente. Aver si trealmente soluciona algo.
- Metadata : Este es una gran caracteristica, pero esta demasiado verde. Va a conseguir que por ejemplo la documentacion sea mucho mas legible y util.
- varags : Esta es otra caracteristica un tanto indiferente, o por lo menos menor, aunque en cierto modo bastante util podemo pasarle multiples parametros a un metodo, y este los almacenara dentro de un array de objetos.
public static void myprintf(String seperator, Object[] args...) {
String sep = "";
for (Object o : args) {
System.out.print(sep);
System.out.print(o);
sep = seperator;
}
System.out.println();
}
Bueno un pequeño repaso antes de meternos mas a fondo con el. Hay mas novedades, como la que comente en el ultimo post Overriden Return Type. Como decian en la tele...Mañana mas.
( sep 10 2004, 02:17:39 PM CEST )
Permalink
lunes septiembre 06, 2004
Tigre : Overriding Return Types No solo Rugi va a hablarnos del tigre, los demas tambien somos un poco zoologo
.
Una de las nuevas caracteristicas que incorpora el tigre ;), es la capacidad de sobreescirbir el valor de retorno de un metodo al extender una clase. Esto al principio suena un poco raro, y al final a mi me sigue sonando igual de raro. Para que me sirve a mi esto. Bueno tomare un ejeplo prestado del ultimo libro de O`really sobre el tema "Java 1.5 Tiger: A Developer's Notebook"
class Point2D {
protected int x, y;
public Point2D( ) {....}
public Point2D(int x, int y) {..... }
}
class Point3D extends Point2D {
protected int z;
public Point3D(int x, int y) {....}
public Point3D(int x, int y, int z) {....}
}
class Position2D {
Point2D location;
public Position2D(int x, int y) {...}
public Point2D getLocation( ) {
return location;
}
}
class Position3D extends Position2D {
Point3D location;
public Position3D(int x, int y, int z) {...}
public Point3D getLocation( ) {
return location;
}
}
Pero claro, como siempre algo huele mal en dinamarca, donde esta la trampa, por que no se a los demas a mi crear un objeto padre con una interfaz definida, para luego heredar de el y modificar esa interfaz no me parece el mejor método de mantener la "insolation" (lo siento no me sale la palabra en español). Ojo una cosa diferente es sobrecargar un metodo con lo cual no variamos la interfaz, sino que la ampliamos creando un nuevo metodo y otra modificar la interfaz de un metodo que ya existe.
EMHO, que no es nada comparada con la de David Flanagan, Brett McLaughlin que no son dos desconocidos, este es un mal ejemplo, seguramente por que esta no es una buena caracteristica (si alguien ve algun caso en el que lo fuera podria indicarla?)
interface Point {}
class Point2D extend Point{...
}
class Point3D extends Point2D {....
}
class Position2D {
Point2D location;
public Position2D(int x, int y) {...}
public Point getLocation( ) {
return location;
}
}
class Position3D extends Position2D {
Point3D location;
public Position3D(int x, int y, int z) {...}
public Point getLocation( ) {
return location;
}
}
Esto seria solo un ejemplo de mejora, por que se podria afinar muchisimo mas ahora ..... ¿es solo un mal ejemplo o es una mala caracteristica del lenguaje?
( sep 06 2004, 07:43:12 PM CEST )
Permalink
miércoles agosto 18, 2004
Esas malditas custom tags !!!! Hay ocasiones en que me desespero, hace no mucho me encontre realizando un "refactoring" completo de una aplicación para un cliente, la aplicación en si era bastante sencilla, y en principio yo solo tenia que agregar un nuevo tipo de servicio, pero en una de las pocas ocasiones en que el cliente pide consejo y no solo "quiero que", ya que habia consultado antes con otras "consultoras" y le habian dicho que era mejor hacer una aplicacion nueva. Yo me ofreci a hacerle un "buen precio" (demasiado bueno diria yo). Bueno a lo que voy.
No hay nada que me desepere mas que ver como alguien que se salta por la cara las mas basicas tecnicas de diseño, en este caso toda lógica de acceso a datos estaba embebida en unas custom tags que llamaba desde las propias JSP.
Pues en estas andaba yo mosqueado cuando derrepente me vuelvo a encontrar con esto, pero en plan OS, y por duplicado en dos proyectos diferentes y uno es nada menos que JSTL con sus etiquetas con para el manejo de SQL y el otro es un proyecto de
etiquetas para hibernate a lo que yo me pregunto. ¿El mundo se ha vuelto loco? ¿se me esta derritiendo el cerebro, me estoy volviendo tonto y esto es lo correcto? ¿ES la sucion mas comoda, la solucion correcta?.
Tengo que hacerme un hombre y seguir el koan de Aitor
¿Librerias?. Are you kidding?. I'm a fucking bloody XSL powered man!.
( ago 18 2004, 11:58:05 PM CEST )
Permalink
martes julio 27, 2004
Toolkit. Con la llegada del verano aumenta las gaas del aire libre, y anoche tomando una cervecita con gente del gremio estuvimos hablando de que herramientas usa cada uno. Asi que he decidido hacer limpieza dentro de mi caja de herramientas
- Entorno de desarrollo : Eclipse+Lomboz+ant, estoy muy contento con el, por ahora me resuelve todas mis necesidades, excepto cuando tengo que hacer algo en Swing (aunque ha decir verdad, las pequeñas aplicaciones standalone, las desarrollo en VB...no por velocidad sino por tiempo de desarrollo). Tengo que probar el pack que lanzo IBM hace unos dias a ver que tal, pero tampoco es urgente. Echo de menosa mi querido JEdit, pero se queda muy atras en prestaciones aunque cuando me pongo nostalgico lo uso :)
- Contenedor de Servlet : Tomcat, sin competencia por documentacion, tambien me gusto hace tiempo resin, pero no es lo mismo.
- O/R mapping : Hibernate. pero no me termina de agradar estar atado a una solucion no estandar, preferiria un motor JDO 2.0 pero habra que esperar, no suelo usar EJB, aunque despues de echarle un vistazo a la especificacion 3.0 estoy a la espera de un contenedor que lo implemente para experimentar
- MVC : Struts, rodillo apache... no me gusta, y he intentado buscar otras propuesta como tapestry y webwork, pero no. Tengo ganas de darle una oportunidad a JSF, pero esperare a que este mas maduro.
- Test unitario : JUnit, gracias Junit, tengo que escribir un tutorial sobre est para devolverle algo a este producto, quien se anima conmigo, un monton de mock objects, sacados de la red, aunque estoy por crear un proyecto OS, no se, tampoco creo que sea de mucha utilidad , ya veremos si me animo.
- Loggings : Libreria propietaria, mia y solo mia, no merece la pena publicarla como OS por que existen muchas y mejores que la mia.
- Librerias de apoyo en la capa de presentacion : He usado varias, pero ahora solo uso JSTL, cada vez me convence menos, quizas lo que me convezca menos sea JSP, no se. tendre que probar los motores de plantillas, aunque lo que de verdad me gustaria es no volver a tocar la capa de presentacion nunca mas :)
- Bases de datos : MySql, Oracle. Me gusta Oracle, me gusta mucho, mas que DB2
- Contenedor J2EE : JBoss/Weblogic, este si que quiero cambiarlo, veremos que pasa con Geronimo, pero si tengo tiempo quiero ponerme conj Jonas, Alguna experiencia en produccion ??
- Code Generation : Xdoclet, anque creo que este proyecto tendera a desaparecer para crear una forma estandar de metadatos, o eso espero.
- Otros :
- Jakarta commons es un básico para todos.
- JGoodies : look & Feel
- ArgoUML : modelado, pero esta verde, a veces no saca bien el código y me gustaria que e pudiese crear ejecutables a traves de MDA, como en tipo androMDA
- Experimentando :
- Spring : para despliegue de JavaBeans, integracion con hibernate y AOP
- AspectJ : AOP, pero el tema lo veo muy verde
- picocontainer : no me ha gustado, que le vamosa hacer.
Pues esa son mis herramientas, algunas etan ya viejas y otras nuevecitas, que marca de alicates usais vosotros?
( jul 27 2004, 11:19:33 PM CEST )
Permalink
lunes febrero 09, 2004
El patron DAO I parte Todos nos hemos tenido que pelear alguna vez con la persistencia de nuestros datos. Yo hoy voy ha tratar este tema que me ha traido mas de un problema y mas de un dolor de cabeza, y que hoy he visto publicado en el blueprint de
Java Adventure. Como siempre teneis la oportunidad/deber de corregirme.
Aunque el patron DAO es en principio un parton de J2EE, tambien puede aplicarse en cualquier aplicación que necesite mantener sus datos de forma persistente.
Proposito
El proposito del patron DAO es crear un contrato para manejar la persistencia de una informacion ocultando la implementacion de esta persistencia. En un caso ideal deberiamos crear una capa de persistencia que aislara todo acceso a información persistente.
Aislando la lógica de negocio de la capa de persistencia.
Debemos el patron Data Access Object (DAO) para abstraer y encapsular los accesos, gestionar la conexiones a la fuente de datos y obtener los datos almacenados.
En este pimer post tratare lo esencial del patron DAO y como relacionarlo con otros patrones, por ejempo el Patron Factory o el Value Object. en el siguiente tratamos relacionados con la transaccionalidad y por ultimo analizare otras soluciones a la persistencia de dtaos.
Las operaciones básicas que suelen estar asociadas a la gestión de datos se denominan CRUD (create, read, update, delete).
Estrategias
Asociacion Directa
La estrategia mas simple es que a cada objeto de negocio que necesite persistencia se le asocie un objeto DAO. De esta manera un objeto Cliente tendra asocioado un objeto clienteDAO.
Un claro inconveniente de esta estrategia es que cada objeto de negocio solo puede acceder a una fuente de datos atraces de su propio DAO, asi si la fuente es una BBDD no podra cambiar a un XML
Data Access Object Factory
Para evitar lo inconvenientes de la asociacion directa podemos crear un patrón factoria[GoF] de Objetos DAO, asi podremos añadir nuevos tipos de DAOs a una clase de negocio. Por ejemplo ClienteMySQLDAO, ClienteOracleDAO o ClienteXmlDAO
Abstract Factory Data Access Object
Una forma de crear cohesion dentro de la capa de persistencia es utilizar un abstrart factory[GoF] que nos devuelva la instancia XxxfactoryDAO de cualquier objeto de negocio. Veamos el codigo de un DAOFactory típico
import javax.naming.NamingException;
import javax.naming.InitialContext;
public class DAOFactory {
public static Object getDAO(String daoEnvEntry) throws DAOSystemException {
try {
InitialContext ic = new InitialContext();
String className = (String) ic.lookup(daoEnvEntry);
return Class.forName(className).newInstance();
} catch (NamingException ne) {
throw new DAOSystemException("DAOFactory.getDAO(" + daoEnvEntry +"): NamingException while getting DAO type : \n" + ne.getMessage());
} catch (Exception se) {
throw new DAOSystemException("DAOFactory.getDAO(" + daoEnvEntry +"): Exception while getting DAO type : \n" + se.getMessage());
}
}
}
Transfer Object Collection
Externalizacion de las datos
El acceso a distintas fuentes de datos hace que cada objeto DAO en particular deba conocer ciertos parametros de configuracion, por ejemplo la conexion a la base de datos o una sentencia SQL. Esto lo podriamos hacer mediate un ficher properties o un archivo XML
Generalizar Data Access Object
Podemos minimizar el numero de objetos DAOs o anticiparnos a la necesidad de tener que crear nuevos objetos para distintas base de datos, si hacemos uso de la externalizacion de los parametros de configuración y creamos un objeto DAO que cargue de forma uniforme. Por ejemplo ellos DAO clienteMySQLDAO y clienteOracleDAO, solo variarian en la conexion y quizas en la consulta SQL, por lo tanto seria mejor un objeto ClienteBaseDatosDAO y un fichero que externalice la configuracion para cada BBDD
Un DAO tipico
La típica arquitectura DAO suele constar al menos de
- Una clase DAO factory ejemplo
- Una interface DAO ejemplo
- Una clase concreta que implementa la interface DAOejemplo
- Algun tipo del Value objectsejemplo
ventajas
- Centralizar el control de acceso dato
- Transparencias en el acceso a datos
- Facilita la migracion
- organiza todos los accesos a datos en una capa separada
desventajas
- Añade una nueva capa
- Necesita crearse una geraquia de clases
- Aumenta la complegidad del diseño inicial
( feb 09 2004, 03:50:43 PM CET )
Permalink
domingo noviembre 02, 2003
EL patron DAO 1ª parte Todos nos hemos tenido que pelear alguna vez con la persistencia de nuestros datos. Yo hoy voy ha tratar este tema que me ha traido mas de un problema y mas de un dolor de cabeza, y que hoy he visto publicado en el blueprint de
Java Adventure. Como siempre teneis la oportunidad/deber de corregirme.
Aunque el patron DAO es en principio un parton de J2EE, tambien puede aplicarse en cualquier aplicación que necesite mantener sus datos de forma persistente.
Proposito
El proposito del patron DAO es crear un contrato para manejar la persistencia de una informacion ocultando la implementacion de esta persistencia. En un caso ideal deberiamos crear una capa de persistencia que aislara todo acceso a información persistente.
Aislando la lógica de negocio de la capa de persistencia.
Debemos el patron Data Access Object (DAO) para abstraer y encapsular los accesos, gestionar la conexiones a la fuente de datos y obtener los datos almacenados.
En este pimer post tratare lo esencial del patron DAO y como relacionarlo con otros patrones, por ejempo el Patron Factory o el Value Object. en el siguiente tratamos relacionados con la transaccionalidad y por ultimo analizare otras soluciones a la persistencia de dtaos.
Las operaciones básicas que suelen estar asociadas a la gestión de datos se denominan CRUD (create, read, update, delete).
Estrategias
Asociacion Directa
La estrategia mas simple es que a cada objeto de negocio que necesite persistencia se le asocie un objeto DAO. De esta manera un objeto Cliente tendra asocioado un objeto clienteDAO.
Un claro inconveniente de esta estrategia es que cada objeto de negocio solo puede acceder a una fuente de datos atraces de su propio DAO, asi si la fuente es una BBDD no podra cambiar a un XML
Data Access Object Factory
Para evitar lo inconvenientes de la asociacion directa podemos crear un patrón factoria[GoF] de Objetos DAO, asi podremos añadir nuevos tipos de DAOs a una clase de negocio. Por ejemplo ClienteMySQLDAO, ClienteOracleDAO o ClienteXmlDAO
Abstract Factory Data Access Object
Una forma de crear cohesion dentro de la capa de persistencia es utilizar un abstrart factory[GoF] que nos devuelva la instancia XxxfactoryDAO de cualquier objeto de negocio. Veamos el codigo de un DAOFactory típico
import javax.naming.NamingException;
import javax.naming.InitialContext;
public class DAOFactory {
public static Object getDAO(String daoEnvEntry) throws DAOSystemException {
try {
InitialContext ic = new InitialContext();
String className = (String) ic.lookup(daoEnvEntry);
return Class.forName(className).newInstance();
} catch (NamingException ne) {
throw new DAOSystemException("DAOFactory.getDAO(" + daoEnvEntry +"): NamingException while getting DAO type : \n" + ne.getMessage());
} catch (Exception se) {
throw new DAOSystemException("DAOFactory.getDAO(" + daoEnvEntry +"): Exception while getting DAO type : \n" + se.getMessage());
}
}
}
Transfer Object Collection
Externalizacion de las datos
El acceso a distintas fuentes de datos hace que cada objeto DAO en particular deba conocer ciertos parametros de configuracion, por ejemplo la conexion a la base de datos o una sentencia SQL. Esto lo podriamos hacer mediate un ficher properties o un archivo XML
Generalizar Data Access Object
Podemos minimizar el numero de objetos DAOs o anticiparnos a la necesidad de tener que crear nuevos objetos para distintas base de datos, si hacemos uso de la externalizacion de los parametros de configuración y creamos un objeto DAO que cargue de forma uniforme. Por ejemplo ellos DAO clienteMySQLDAO y clienteOracleDAO, solo variarian en la conexion y quizas en la consulta SQL, por lo tanto seria mejor un objeto ClienteBaseDatosDAO y un fichero que externalice la configuracion para cada BBDD
Un DAO tipico
La típica arquitectura DAO suele constar al menos de
- Una clase DAO factory ejemplo
- Una interface DAO ejemplo
- Una clase concreta que implementa la interface DAOejemplo
- Algun tipo del Value objectsejemplo
ventajas
- Centralizar el control de acceso dato
- Transparencias en el acceso a datos
- Facilita la migracion
- organiza todos los accesos a datos en una capa separada
desventajas
- Añade una nueva capa
- Necesita crearse una geraquia de clases
- Aumenta la complegidad del diseño inicial
( nov 02 2003, 04:54:17 PM CET )
Permalink
martes agosto 19, 2003
Front Controller + gestor de eventos ( 2ª parte ) En los post anteriores hablabamos sobre el patron front controller, ( tambien hablaron Al y Álvaro). Este post es un poco largo y contiene bastante codigo. Para ver un esquema que sigue el flujo de una peticion ver esta secuencia y para ver un diagrama de las clases finales ver aqui. En este post seguire con dos aspectos que deje fuera:
- Un sistema para redireccionar (sendRedirect / forwad).
- Un gestor de eventos.
Antes que nada decir que este ejemplo no pretende ser un framework real, ni nada parecido, sino solo un conjunto de clases que muestren de la manera mas sencilla posible algunos conceptos del front controller (por esto no he querido utilizar XML y minimizar la configuracion en archivos properties ya que no son en si mismo parte del patron)
Redireccionamiento
En la implementacion anterior solo podiamos ir a una vista o a otra accion mediante el metodo sendRedirect. En este caso el primer paso era crear una estructura que almacenase el tipo de respuesta que se debia ejecutar.
public class AccionResult {
private String nombre="";
private String path="";
private boolean forward=true;
/**
* Constructores
*/
public AccionResult(String nombre, boolean forward){
this.nombre=nombre;
this.forward=forward;
}
public AccionResult(String nombre, String path, boolean forward){
this.nombre=nombre;
this.path=path;
this.forward=forward;
}
..... Metodos Getters y Setters
Cambiamos el metodo accion de la interfaz Accion para que en vez de una cadena ahora nos devuelva una instancia de la clase AccionResult
public AccionResult accion();
Y despues añadir a la clase Controlador el metodo enrutar
public void enrutar(AccionResult aResult, HttpServletRequest request,
HttpServletResponse response){
if (aResult.isForward()){
// Lanzo un forward con la request y un response
try {
this.getServletContext().getRequestDispatcher(response.encodeURL(aResult.getNombre())).forward(request,response);
} catch (ServletException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}else{
// Redirecciono a la nueva URL
try {
response.sendRedirect(aResult.getNombre());
} catch (IOException e) {
e.printStackTrace();
}
}
}
Y ahora solo con cambiar la accion req.sendRedirect por this.enrutar(aResult,rep,res) del metodo procesar del controlador podemos elegir el tipo de redireccionamiento. El problema de esta solucion es que los valores del la clase AccionResult son introducidos directamente enel codigo, cuando lo ideal seria poder definirlos en un fichero (xml o properties), por ejemplo algo como [forward value="true" result="exito" direccion="/RegistroExito.jsp"] para desacoplar las JSPs de las Acciones algo mas.
Gestion de eventos
El segundo punto, creo que va a ser mas polemico (ya que aqui si que he encontrado cierta dificultad en cuanto al concepto en si mismo). A priori habia dos casos que se podrian tratar:
- ActionEvents : Eventos que se disparan antes o despues de que se vaya a ejecutar una accion.
- ChangeValueEvents : Eventos que se ejecutan cuando algun valor o estado de la aplicacion cambia (este caso no lo voy a contemplar)
El esquema basico del funcionamiento del front controller que he diseñado viene dado por esta
secuencia. Como vemos existen unas clases que ejecutaran cada evento particular, estas clases implementan la interfaz AccionListener:
public interface AccionListener {
public String doBeforeAccion() throws ServletException;
public String doAfterAccion() throws ServletException;
}
Existe una clase abstracta apartir de la que heredan todos los eventos AccionEvent :
public abstract class AccionEvent implements AccionListener {
public static final int BEFORE_ACCION=0,AFTER_ACCION=1;
int tipoEvento;
public AccionEvent(int tipoEvento) {
this.tipoEvento=tipoEvento;
}
.....Metodos Getters y Setters
}
Y la interfaz accion se amplia con los metodos necesarios para añadir, eliminar y disparar los eventos.
public void dispararEvents(int tipoEvento);
public void addEventListener(AccionListener aListener);
public void removeEvent(AccionListener aListener);
Asi mismo estos metodos son implementados por la clase AbstracAccion, del que heredaran ahora las acciones.
protected List eventListeners = new ArrayList();
public void dispararEvents(int tipoEvento) {
Iterator i = eventListeners.iterator();
AccionEvent aListener = null;
while (i.hasNext()) {
aListener =(AccionEvent) i.next();
try{
if (aListener.getTipoEvento()==tipoEvento)
aListener.doBeforeAccion();
else if (aListener.getTipoEvento()==tipoEvento)
aListener.doAfterAccion();
}catch(ServletException se){
System.out.println("Error al lanzar un Evento del tipo " + tipoEvento);
}
}
}
.... Los otros dos metdos .....
}
Resumiendo el esquema de las clases queda
asi. Ya podeis despedazarme por los errores que he cometido. ¿Algun problema de concepto?. ¿Alguna sugerencia?
( ago 19 2003, 06:31:30 PM CEST )
Permalink
miércoles agosto 13, 2003
Revisado : El patron Front Controller 1ª parte Bueno siguiendo el consejo de
Al, he decidido cambiar la implementacion del ActionFactory para que solo se instancie una vez cada accion y luego se reutilice esta instancia el resto de las veces.
public class AccionFactory {
// tabla para guardar las acciones
private static Hashtable mapaAcciones = new Hashtable();
public static Accion getAccion(String accion){
Accion action = (Accion) mapaAcciones.get(accion);
if (action==null){
try {
action = (Accion)Class.forName(accion).newInstance();
mapaAcciones.put(accion, action);
} catch (InstantiationException e) {
System.out.println("Error al instanciar la clase");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("Acceso Ilegal a no se que ¿?");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("Tas tonto esa clase no existe");
e.printStackTrace();
}
}
return action;
}
}
Bueno en principio cada clase que implemente accion se instancia una unica vez y es almacenada en una Hashtable. Pero no daria esto problemas de concurrencia si se solicitan a la vez dos instancias de esa accion? no termino de verlo del todo claro... voy a darle un par de vueltas a ver si veo donde me he perdido. + criticas please...
Bueno a parte de esto he hecho una pequeña modificacion para que el fichero de configuracion quedase tal que asi:
comprar=comprarAccion
elegir=elegirAccion
devolver=devolveAccion
buscar=buscarAccion
inicio=inicioAccion
Que siempre queda algo mas fino. Para extraer la accion de la URI he añadido el metodo
private String getClassName(String nombre){
int barra = nombre.lastIndexOf("/");
int punto = nombre.lastIndexOf(".");
if ((barra<=0)&&(punto<=0)) return nombre;
return nombre.substring(barra+1,punto);
}
PD Al, de esta semana no pasa que no me baje el codigo y la documentacion de Cañamo. No se si sabre implementar algo o sugerir alguna mejora del diseño, pero por lo menos que no se diga que no lo intento (Que despues hablamos de sensacion de comunidad y de implicacion, y yo soy el primero en dar mal ejemplo). Ademas que ya has tirado unas cuantas indirectas y muchos nos hacemos lo locos, ya va siendo hora.
( ago 13 2003, 05:35:22 PM CEST )
Permalink
martes agosto 12, 2003
El patron Front Controller 1ª parte Como comente en mi ultimo post he estado dando un pequeño curso sobre J2EE (Bueno mas bien sobre Servlet y JSP, pero eso es otra historia). En la aplicacion del ultimo dia presentaron un Servlet que implantaba el patron Front Controller de la forma
public class MiServlet extends HttpServlet{
public void doPost(HttpServletRequest request, HttpServletResponse response) {
String action = request.getParameter("action");
if(action.equals("alta")){
// codigo del alta
}else if(action.equals("baja")){
// codigo para dar de baja
else if (....){
}....
}
}
No hace falta discutir lo malo de esta forma de implentarlo. Como soy bastante quisquilloso decidi implementar uno por mi parte. Para empezar me marque una serie de objetivos:
- Asociacion de las URI a las acciones mediante un mapeo en un fichero de propiedades. Elegi este tipo de fichero para simplificarlo al maximo, supongo que lo suyo es hacerlo con un fichero XML... todo se andara
- Carga dinamica de las clases
- Diseño de una interfaz Accion al estilo de Action es Struts
- Utilizacion del patron DAO para el objeto que maneja el mapeo y el patron factory para la clase que devuelve las acciones
Empece por definir la interfaz Accion de la forma mas simple posible. La idea de crear una interfaz comun a todas las acciones es que obliga a que todas inserten el codigo que se ejecutara dentro de un metodo.
public interface Accion {
public String accion();
}
Para obtener una clase pense en un patron factory, creo que es una buena eleccion y que la tarea se ajusta a la definicion de este patron. Posiblemente seria necesario declarar el metodo como syncrhonized, pero no estoy del todo seguro. El objetivo de esta clase es que dado el nombre de otra clase nos devuelva una instancia de esta.
public class AccionFactory {
public static Accion getAccion(String accion){
Accion action = null;
try {
action = (Accion)Class.forName(accion).newInstance();
} catch (InstantiationException e) {
System.out.println("Error al instanciar la clase");
e.printStackTrace();
} catch (IllegalAccessException e) {
System.out.println("Acceso Ilegal a no se que ¿?");
e.printStackTrace();
} catch (ClassNotFoundException e) {
System.out.println("Tas tonto esa clase no existe");
e.printStackTrace();
}
return action;
}
}
Ahora tocaba buscar una forma de almacenar el mapeo, como ya explique me decidi por un fichero de propiedades por su simplicidad, el nombre del fichero esta directamente implementado en el codigo, aunque seria muy sencillo pasarselo como parametro de inicializacion al servlet y despues recuperarlo alli.
public class MapeoAccionesDAO {
private Properties mapa;
public MapeoAccionesDAO(String configuracion){
mapa = new Properties();
try {
InputStream iStream = new FileInputStream(configuracion);
mapa.load(iStream);
} catch (FileNotFoundException e) {
System.out.println("Error fichero no encontrado");
e.printStackTrace();
} catch (IOException e) {
System.out.println("Error IOException no se porque da este error");
e.printStackTrace();
}
}
public String getNombreAccion(String requesURI){
return mapa.getProperty(requesURI);
}
}
Ya por ultimo (para alivio de los que habeis leido tantas lineas de codigo) solo faltaba implementar el servlet que actua como controlador. Tambien opte por hacerlo de la forma mas sencilla posible, eliminando por ejemplo la posibilidad de decidir si lo que quiero es ralizar un forward o un sendRedirect (esto lo hare un poco mas adelante).
public class Controlador extends HttpServlet {
/*
* Usaremos un objeto que nos mapee las URI con las
* clases accion asociadas a esa URI
*/
private MapeoAccionesDAO acciones;
public void init(ServletConfig config) throws ServletException {
super.init(config);
/*
* Inicializamos el mapeo usando un patron DAO
*/
ServletContext sc = config.getServletContext();
String configuracion = sc.getRealPath("configuracion.properties");
acciones = new MapeoAccionesDAO(configuracion);
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
this.procesar(request,response);
}
protected void doPost( HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
this.procesar(request,response);
}
private void procesar( HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
Accion action = null;
/*
* Extraemos la URI de la solicitud
* y se la pasamos al properties como clave
*/
String accion = acciones.getNombreAccion(request.getRequestURI());
System.out.println("Voy a realizar la accion : " + accion);
/*
* Instanciamos la clase que nos devuelve el properties
* y usamos este como zona de mapeo
* y todo esto usando un patron Factory
*/
action = AccionFactory.getAccion(accion);
String nuevaURL = action.accion();
response.sendRedirect(nuevaURL);
}
}
un ejemplo del mapeo seria el siguiente fichero :
comprar.do=comprarAccion
/mittienda/elegir.do=org.mitienda.elegirAccion
/mittienda/devolver.do=org.mitienda.devolveAccion
/mittienda/buscar.do=org.mitienda.buscarAccion
/mittienda/inicio.do=inicioAccion
Pues esto es lo que he hecho, no se si sigue a rajatabla el patron front controller o si he metido la pata, asi que espero opiniones, sugerencias y sobre todo críticas (que es de donde + se aprende). Quedan muchos aspectos por hacer, pero solo queria tener una idea de como funcionaba.
PD: es mi primer post con lineas de codigo :-)
( ago 12 2003, 11:48:41 PM CEST )
Permalink