<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-35788871</id><updated>2011-09-07T00:12:36.430-07:00</updated><title type='text'>Andrés Testi Hispano</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://andrestestihispano.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://andrestestihispano.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Andrés Testi</name><uri>http://www.blogger.com/profile/16389222274573646435</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>4</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-35788871.post-116143234628033098</id><published>2006-10-21T04:52:00.000-07:00</published><updated>2006-10-21T05:21:08.306-07:00</updated><title type='text'>JBoss AS 4.0.5 Liberado</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/6568/3888/1600/jbosslogo.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://photos1.blogger.com/blogger/6568/3888/320/jbosslogo.gif" alt="" border="0" /&gt;&lt;/a&gt;Ha sido liberada la versión 4.0.5  del &lt;a href="http://www.jboss.com/products/jbossas"&gt;JBoss Application Server&lt;/a&gt;, que certifica la implementación de EJB3 al 100%, disponiendo de &lt;a href="http://www.hibernate.org/"&gt;Hibernate 3.2&lt;/a&gt; (liberado hace sólo una semana) como proveedor de persistencia nativo. Vale decir que hasta ahora, &lt;a href="http://java.sun.com/javaee/community/glassfish/"&gt;GlassFish &lt;/a&gt;era el único servidor de aplicaciones que soportaba EJB3 de manera completa. El sitio de descarga ofrece la posibilidad de realizar una instalación mediante &lt;a href="http://java.sun.com/products/javawebstart/"&gt;Java Web Start&lt;/a&gt;, algo que nos ahorra un considerable trabajo de configuración.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35788871-116143234628033098?l=andrestestihispano.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrestestihispano.blogspot.com/feeds/116143234628033098/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35788871&amp;postID=116143234628033098' title='71 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116143234628033098'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116143234628033098'/><link rel='alternate' type='text/html' href='http://andrestestihispano.blogspot.com/2006/10/jboss-as-405-liberado.html' title='JBoss AS 4.0.5 Liberado'/><author><name>Andrés Testi</name><uri>http://www.blogger.com/profile/16389222274573646435</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>71</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35788871.post-116047538605830153</id><published>2006-10-10T03:16:00.000-07:00</published><updated>2006-10-10T03:16:26.063-07:00</updated><title type='text'>Framework PRADO libera versión 3.0.4</title><content type='html'>&lt;div style="text-align: justify;"&gt;Cuando se habla de PHP, se piensa en la programación estructurada, en el código espaguetti, en la falta de convención de nombres, en la baja escalabilidad, y en todos los malos vicios achacables al desarrollo de software amateur. Sin embargo, a partir de &lt;a href="http://www.php.net/downloads.php#v5"&gt;PHP 5&lt;/a&gt; la cosa empieza a cambiar, porque han nacido proyectos que ya pasan de ser simples librerías como &lt;a href="http://pear.php.net/"&gt;PEAR&lt;/a&gt; o &lt;a href="http://www.aditus.nu/jpgraph/"&gt;JPgraph&lt;/a&gt;, a ser verdaderos frameworks. Tal es el caso de &lt;a href="http://cakephp.org/"&gt;Cake&lt;/a&gt; (inspirado en &lt;a href="http://www.rubyonrails.org/"&gt;Ruby On Rails&lt;/a&gt;), &lt;a href="http://www.mojavi.org/"&gt;Mojavi&lt;/a&gt; (un MVC parecido a &lt;a href="http://struts.apache.org/"&gt;Struts&lt;/a&gt;), &lt;a href="http://www.symfony-project.com/"&gt;Symfony&lt;/a&gt; , &lt;a href="http://www.blueshoes.org/"&gt;BlueShoes&lt;/a&gt;, &lt;a href="http://www.pradosoft.com/"&gt;PRADO&lt;/a&gt;, y otros tantos. Desde mi punto de vista, PRADO es el más interesante de todos, porque plantea una solución moderna, se basa en el concepto de aplicación (lo contrario de páginas independientes), es totalmente orientado a eventos y a componentes, es fácil de aprender, y tiene una excelente documentación. Según sus creadores, está inspirado en &lt;a href="http://tapestry.apache.org/"&gt;Tapestry&lt;/a&gt;, Delphi y Visual Basic. La idea central es que cada página tiene un ciclo de vida y un estado. La manera de implementar una página es mediante un template y una clase asociada (al estilo de Tapestry). Cada página es un componente que a su vez puede estar compuesto por otros componentes. Los componentes tienen una manera de "renderizarse" y pueden responder a eventos. Esta forma de trabajar hace que las aplicaciones sean súmamente reutilizables y que incluso, nos podamos dedicar a desarrollar componentes separados, como podría ser una barra de menúes, y luego embeberlos en cada aplicación en la que los necesitemos. En el foro hay un &lt;a href="http://www.pradosoft.com/forum/index.php/board,10.0.html"&gt;repositorio de componentes&lt;/a&gt; en el que los aficionados suben sus propios desarrollos.&lt;br /&gt;A partir de la versión 3, el framework añade uso transparente de &lt;a href="http://es.wikipedia.org/wiki/AJAX"&gt;AJAX&lt;/a&gt; en los denominados &lt;span style="font-weight: bold;"&gt;&lt;a href="http://www.pradosoft.com/forum/index.php/board,26.0.html"&gt;Active Controls&lt;/a&gt; &lt;/span&gt;cuyo nombre e idea fueron &lt;a href="http://www.pradosoft.com/forum/index.php/topic,2453.0.html"&gt;sugeridas por mí&lt;/a&gt; en su foro, aunque jamás incluyeron fui mencionado en su documentación. De todos modos no les guardo rencor, aunque nunca más pienso postear nada en su foro ( que se consigan sus propias ideas, je! ).&lt;br /&gt;Hace unos días anunciaron la &lt;a href="http://www.pradosoft.com/download/"&gt;release 3.0.4&lt;/a&gt; del producto, que es la que ocupa el título de esta nota.&lt;br /&gt;Como detalle interesante, puedo mencionar que unos años antes de PRADO apareció &lt;a href="http://bif.lunix.com.ar/"&gt;BIF&lt;/a&gt;, un framework de concepto y apariencia muy similares a PRADO. Este framework fue desarrollado por Nicolás Cesar, un muchacho de Santa Fe. Lamentablemente no llegó a ser muy popular, pero podríamos considerar que fue pionero en el concepto.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35788871-116047538605830153?l=andrestestihispano.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrestestihispano.blogspot.com/feeds/116047538605830153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35788871&amp;postID=116047538605830153' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047538605830153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047538605830153'/><link rel='alternate' type='text/html' href='http://andrestestihispano.blogspot.com/2006/10/framework-prado-libera-versin-304.html' title='Framework PRADO libera versión 3.0.4'/><author><name>Andrés Testi</name><uri>http://www.blogger.com/profile/16389222274573646435</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35788871.post-116047530335848284</id><published>2006-10-10T03:14:00.000-07:00</published><updated>2006-10-10T03:15:03.366-07:00</updated><title type='text'>Annotation Processing en JDK6 - Propuesta Final</title><content type='html'>&lt;div style="text-align: justify;"&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;En mi primer post tengo el agrado de comunicarles que fue recientemente liberada la proposición final de la especificación del &lt;span style="font-weight: bold;"&gt;Pluggable Annotation Processing&lt;/span&gt;. Para quienes jamás oyeron hablar de esta funcionalidad del JDK, voy a hacer un breve resúmen. Resulta que es posible hacer un preprocesamiento de annotations en tiempo de compilación, es decir, algo parecido a lo que hacemos con las macross de C, pero en una manera súmamente typesafe. Esta característica, nos brinda la posibilidad de generar clases auxiliares que luego serán utilizadas en tiempo de ejecución, a la vez que también nos permite realizar chequeos de consistencia sobre las annotations y lanzar warnings y/o errores de compilación. Con este nuevo artilugio, java podría posicionarse en el top de la metaprogramación, incluso por encima de lenguajes que hoy son venerados por los autodenominados &lt;a href="http://www.pragmaticprogrammer.com/"&gt;programadores pragmáticos&lt;/a&gt;, como pueden ser &lt;a href="http://www.ruby-lang.org/"&gt;Ruby&lt;/a&gt; y &lt;a href="img/gl.link.gif"&gt;Python&lt;/a&gt; (es una pena que estos dos buenos lenguajes de script hayan engendrado toda esta generación de trolls).&lt;br /&gt;La historia nos dice que el concepto de preprocesamiento en java comenzó con la misma aparición de las annotations, es decir en el &lt;span style="font-weight: bold;"&gt;JDK5&lt;/span&gt;,  por medio del API denominado &lt;span style="font-weight: bold;"&gt;Annotation Processing Tool&lt;/span&gt; o &lt;span style="font-weight: bold;"&gt;APT&lt;/span&gt; (nombre muy mal elegido porque se presta a confusiones con el famoso comando Debian). Este API consiste en una serie de clases que nos permiten registrar "listeners" de procesamiento y, por medio del patrón &lt;a href="http://en.wikipedia.org/wiki/Visitor_pattern"&gt;Visitor &lt;/a&gt;(muy utilizado en los procesadores de XML), recorrer las declaraciones asociadas a cada annotation que queremos procesar. Las declaraciones nos llegan en la forma de metadatos, pero al ser estas analizadas en tiempo de compilación, no se utiliza la API &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/reflection/index.html"&gt;&lt;span style="font-weight: bold;"&gt;Reflection&lt;/span&gt;&lt;/a&gt;, porque la misma supone la existencia de un entorno de ejecución. En cambio se utilizan unos objetos denominados &lt;span style="font-weight: bold;"&gt;Declarations&lt;/span&gt;, que representan declaraciones "textuales". Una vez que se tienen implementados y compilados estos procesadores, se utiliza el comando &lt;span style="font-weight: bold;"&gt;apt&lt;/span&gt; que preprocesa las clases objetivo con los procesadores de annotation que implementamos anteriormente. Hasta aquí he comentado lo que ocurre con APT en el JDK5, sin embargo en la documentación pertinente, SUN nos aconseja no encariñarnos con la actual especificación porque está sujeta a cambios. Y aquí es en donde entra en acción el JDK6, mejor conocido como Mustang. Por suerte, nuestros amigos se dieron cuenta de que no tenia sentido tener el comando apt por un lado y el javac por otro, y decidieron fundirlos en un único comando javac. Además, reordenaron el API que anteriormente se encontraba dentro de un paquete propietario, de los nunca bien ponderados &lt;span style="font-weight: bold;"&gt;com.sun&lt;/span&gt;, y lo introdujeron dentro de un subpaquete del &lt;span style="font-weight: bold;"&gt;javax.&lt;/span&gt; Con ésta nueva especificación, para registrar un procesador de annotations, simplemente debemos incluir una implementación de la clase AbstractProcessor dentro del classpath que utilizamos para compilar.&lt;br /&gt;Para que mi explicación sea un poco más concreta, les muestro cómo se vería un procesador de annotations en JDK6:&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import javax.annotation.processing.*;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import static  javax.lang.model.SourceVersion.*;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import javax.lang.model.element.*;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import javax.lang.model.type.*;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import javax.lang.model.util.*;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;import java.util.Set;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;// Indicamos que annotation queremos preprocesar.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;// El '*' significa 'todas', como no podia ser de otra manera&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;@SupportedAnnotationTypes("*")&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;// Que version del JDK utilizamos?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;@SupportedSourceVersion(RELEASE_6)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;// Implementamos un nuevo procesador de annotations&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;public class HelloWorldProcessor extends AbstractProcessor {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  // Este metodo es invocado cuando el compilador esta procesando&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  // una declaracion. RoundEnvironment contiene los metadatos asociados&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  // a la declaracion, ademas de un gestor de mensajes que nos permite&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  // emitir warnings y/o errores de compilacion&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  public boolean process(Set annotations,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;         RoundEnvironment roundEnv) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;         if (!roundEnv.processingOver()){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;          // hacemos que el compilador imprima un mensaje           &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;            processingEnv.getMessager().printNotice("Procesando una annotation");&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;         }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;     return false;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(0, 102, 0);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;br /&gt;El código anterior no tiene intenciones de abarcar el tema en profundidad, pero sirve para tener una idea de lo que estamos hablando.&lt;br /&gt;Para variar, el concepto del preprocesamiento me parece fantástico, pero para mi gusto el API deja bastante que desear, sobre todo porque sólo permite evaluar declaraciones, y no expresiones o secuencias de código, que son los lugares en los que realmente sería útil.&lt;br /&gt;Reconozco que sé poco del tema, pero creo que ésta capacidad permitiría extender el lenguaje de maneras nunca antes vistas. Por ejemplo, se podrían diseñar verdaderos frameworks de AOP autocontenidos, sin la necesidad de utilizar contenedores externos como el JBoss ni precompiladores como el AspectJ.&lt;br /&gt;Sólo espero que perfeccionen el API para el JDK7, porque aún lo veo muy verde.&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;&lt;br /&gt;Más información:&lt;br /&gt;&lt;br /&gt;- &lt;a href="http://jcp.org/aboutJava/communityprocess/pfd/jsr269/index.html"&gt;JSR-000269&lt;/a&gt;&lt;br /&gt;- &lt;a href="http://blogs.sun.com/darcy/category/Annotation%2BProcessing"&gt;Blog del encargado del API&lt;/a&gt;&lt;br /&gt;- &lt;a href="http://download.java.net/jdk6/docs/api/javax/annotation/processing/package-summary.html"&gt;Javadoc&lt;/a&gt;&lt;br /&gt;- &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/apt/GettingStarted.html"&gt;Minitutorial de APT en JDK5&lt;/a&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35788871-116047530335848284?l=andrestestihispano.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrestestihispano.blogspot.com/feeds/116047530335848284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35788871&amp;postID=116047530335848284' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047530335848284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047530335848284'/><link rel='alternate' type='text/html' href='http://andrestestihispano.blogspot.com/2006/10/annotation-processing-en-jdk6.html' title='Annotation Processing en JDK6 - Propuesta Final'/><author><name>Andrés Testi</name><uri>http://www.blogger.com/profile/16389222274573646435</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-35788871.post-116047523003412459</id><published>2006-10-10T03:10:00.000-07:00</published><updated>2006-10-10T03:13:50.053-07:00</updated><title type='text'>Propuesta para Consultas Implícitas en EJB3</title><content type='html'>&lt;style type="text/css"&gt;  &lt;!--   @page { size: 21cm 29.7cm; margin: 2cm }   P { margin-bottom: 0.21cm }  --&gt;  &lt;/style&gt;  &lt;p style="margin-bottom: 0cm;" align="justify"&gt; Al trabajar con tecnología ORM, normalmente se sugiere dividir la lógica de negocios en dos componentes arquitectónicos. Por un lado tenemos la capa de persistencia, que agrupa a los  objetos que son representados por entidades en la base de datos. Estos objetos, en principio, sirven como contenedores de información, pero tienen poca funcionalidad asociada, ya que no tienen acceso directo al API de consultas. Para realizar las consultas y el movimiento de la lógica de negocios, exíste la capa de DAO (Data Access Object), que se encarga de gestionar las transacciones, consultas, inserciones, actualizaciones, etc.. Generalmente, se sugiere que exista un DAO por cada clase persistente del modelo. El DAO puede visualizar la capa de persistencia, pero la capa de persistencia no está enterada de la existencia del DAO. Hasta aquí, no pareciera complicarse el trabajo con esta arquitectura. El problema surge con los objetos que tienen relaciones mandatorias sobre otros objetos, es decir, los objetos que mantienen relaciones de padres e hijos (en el sentido de la navegación, no de la herencia). Si tengo que actualizar un objeto hijo ¿Utilizo el DAO asociado al padre, o el DAO asociado al hijo? ¿Y si borro un objeto padre que debe borrar en cascada a sus hijos? ¿Primero invoco el DAO del hijo para borrar a cada instancia por separado?. La respuesta no es simple ni única, pero pareciera coherente, centralizar la mayor cantidad posible de lógica en la capa de persistencia, para aliviar a la capa de DAO y así minimizar las inconsistencias generadas por este patrón de diseño. En este sentido, EJB3 nos ha brindado algunas soluciones, de la mano de los denominados Entity Listeners. Los Entity Listeners nos permiten acceder de manera ortogonal al ciclo de vida de las entidades (CRUD), de una manera centralizada, quitando muchas responsabilidades de la capa de DAO. Por otro lado, la API de Hibernate Validator, también contribuye en este sentido, al agregar capacidades de validación al modelo persistente. Por último, la lógica de consultas que realiza el DAO, se ve también alivianada por las relaciones de las Entidades, que hacen consultas de manera transparente para descongelar los objetos  relacionados con el objeto de interés. Pero hasta el momento, sólo existe esa única contribución al mundo de las consultas transparentes, no hay nada más que lo inherente a las relaciones. Todo el tiempo se nos presentan problemas. Por ejemplo, si el sueldo de un vendedor se calcula sumando el total de las comisiones de sus ventas, debemos realizar una consulta explícita. Para colaborar con la centralización de responsabilidades, podríamos definir la consulta dentro de un Named Query asociado a la clase Vendedor. De todos modos, la única capa de la arquitectura con la responsabilidad y capacidad de ejecutar esa consulta es el DAO:&lt;/p&gt;         &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;@Entity&lt;br /&gt;@NamedQuery(&lt;br /&gt;name=”Vendedor.calcularSueldo”,&lt;br /&gt;query=&lt;/span&gt;&lt;br /&gt;”&lt;span style="font-family:Courier New,monospace;"&gt;SELECT SUM(venta.comision) “ +&lt;/span&gt;&lt;br /&gt;“&lt;span style="font-family:Courier New,monospace;"&gt;FROM Vendedor v JOIN v.ventas venta ” +&lt;/span&gt;&lt;br /&gt;“&lt;span style="font-family:Courier New,monospace;"&gt;WHERE v = :vendedor “&lt;br /&gt;)&lt;/span&gt;&lt;/p&gt;       &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;public class Empleado{&lt;br /&gt;....&lt;br /&gt;@OneToMany(fetch=LAZY, cascade={ALL}, mappedBy=”vendedor”)&lt;br /&gt;private List&lt;venta&gt; ventas;&lt;br /&gt;.....&lt;br /&gt;}&lt;/venta&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;      &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;public class Venta{&lt;br /&gt;.....&lt;br /&gt;@ManyToOne(fetch=LAZY, optional=false)&lt;br /&gt;@JoinColumn(name=”VENDEDOR_ID”)&lt;br /&gt;private  Vendedor vendedor;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;    &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; private Integer comision;&lt;br /&gt;....&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;    &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;@Stateless&lt;br /&gt;public class DaoVendedorBean implements DaoVendedorLocal{&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;@PersistenceContext&lt;br /&gt;private EntityManager em;&lt;/span&gt;&lt;/p&gt;       &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; public Long calcularSueldo(Vendedor v){&lt;br /&gt;return (Long)em.createNamedQuery(“Vendedor.calcularSueldo”)&lt;br /&gt;.setParameter(“vendedor”, v)&lt;br /&gt;.getSingleResult();&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm;" align="justify"&gt;&lt;span style="color: rgb(0, 102, 0);font-family:Courier New,monospace;" &gt;}&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;" align="justify"&gt; Aquí algo parece no estar funcionando del todo bien. Supuestamente, los objetos en OOP tienen métodos propios que nos informan de su estado ¿Por qué debe ser otro objeto el que nos informe del sueldo del vendedor? Podríamos entonces, pensar en un nuevo tipo de inyección denominado Implicit Query. Supongamos que contamos con la siguiente annotation:&lt;/p&gt;     &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;@Retention(RUNTIME)&lt;br /&gt;@Target(METHOD)&lt;br /&gt;public @interface ImplicitQuery{&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;String value();&lt;br /&gt;String parameter() default “this”;&lt;br /&gt;FetchType fetch() default EAGER;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;En donde  &lt;/p&gt;    &lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt; value&lt;/b&gt;:  es el nombre de alguna NamedQuery de la entidad.&lt;br /&gt;&lt;b&gt;parameter&lt;/b&gt;: es el nombre del único parametro por el que se inyecta la entidad analizada. Por default es “this”&lt;br /&gt;&lt;b&gt;fetch&lt;/b&gt;: determina en qué momento se realiza la consulta.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm;"&gt;Entonces podríamos agregar el siguiente campo en la clase vendedor:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;    &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; @ImplicitQuery(&lt;br /&gt;name=”Vendedor.calcularSaldo”,&lt;br /&gt;parameter=”vendedor”&lt;br /&gt;)&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="color: rgb(0, 102, 0);font-family:Courier New,monospace;" &gt; private Long saldo;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;De esta manera podríamos eliminar el método calcularSueldo del DaoVendedor, aliviando aún más la responsabilidad del Dao!!!&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;Adicionalmente, las Implicit Queries traerían otras &lt;b&gt;ventajas&lt;/b&gt;:&lt;br /&gt;&lt;/p&gt; &lt;ul&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;" align="justify"&gt;&lt;b&gt;Anidamiento de consultas  transparente:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt; &lt;/li&gt;&lt;/ul&gt;  &lt;p style="margin-bottom: 0cm;" align="justify"&gt; Supongamos que un vendedor pide adelantos de sueldo, y queremos conocer qué adelantos de sueldo han superado el total de comisiones por ventas que tiene. Esto, en la implementación actual, se haría de la manera siguiente:&lt;/p&gt; &lt;p style="margin-bottom: 0cm;" align="justify"&gt;&lt;br /&gt;&lt;/p&gt;       &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; SELECT v.adelanto&lt;br /&gt;FROM Vendedor v&lt;br /&gt;WHERE v = :vendedor AND v.adelanto &gt; ALL(&lt;br /&gt;SELECT  SUM(venta.comision)&lt;br /&gt;FROM Ventas venta&lt;br /&gt;WHERE venta.vendedor = :vendedor&lt;br /&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm;"&gt; Si tuvieramos Implicit Query, sólo tendríamos que hacer esto:&lt;/p&gt;     &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="color: rgb(0, 102, 0);font-family:Courier New,monospace;" &gt; SELECT v.adelanto&lt;br /&gt;FROM Vendedor v&lt;br /&gt;WHERE v = :vendedor AND v.adelanto &gt; v.sueldo&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Typesafe&lt;/b&gt;:&lt;/li&gt;&lt;/ul&gt;  &lt;p style="margin-bottom: 0cm;" align="justify"&gt; Si asociamos una&lt;b&gt; Implicit Query &lt;/b&gt;a un campo o getter, el contenedor puede detectar en fase de deployment, si la propiedad soporta el tipo de dato retornado por la consulta. Esto ayudaría a detectar tempranamente los errores de tipo, reduciendo la posibilidad de que ocurran en tiempo de ejecución.&lt;/p&gt;  &lt;ul&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;Polimorfismo&lt;/b&gt;:&lt;/p&gt; &lt;/li&gt;&lt;/ul&gt;  &lt;p style="margin-bottom: 0cm; text-align: justify;"&gt; Si además de Vendedores, nuestra empresa cuenta con Administrativos que ganan sus sueldos en función de las horas trabajadas, sería interesante generalizar ambas clases en una superclase Empleado. Las declaraciones quedarían asi:&lt;/p&gt;  &lt;p style="margin-bottom: 0cm;" align="justify"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; public class Empleado{...}&lt;/span&gt;&lt;/p&gt;         &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; @Entity&lt;br /&gt;@NamedQuery(&lt;br /&gt;name=”Administrativo.calcularSueldo”,&lt;br /&gt;query=&lt;br /&gt;”SELECT SUM(ht.cantidad) ” +&lt;br /&gt;“FROM Administrativo a JOIN a.horasTrabajadas ht“ +&lt;br /&gt;“WHERE a = :administrativo”&lt;br /&gt;)&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; public class Administrativo extends Empleado{...}&lt;/span&gt;&lt;/p&gt;         &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;&lt;span style="color: rgb(0, 102, 0);"&gt; @Entity&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;@NamedQuery(&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;name=”Vendedor.calcularSueldo”,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;query=&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;”SELECT SUM(venta.comision) “ +&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;“FROM Vendedor v JOIN v.ventas venta ” +&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;“WHERE v = :vendedor “&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 102, 0);"&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; public class Vendedor extends Empleado{....}&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt; &lt;/p&gt; &lt;p style="margin-bottom: 0cm; text-align: justify;"&gt; Entonces en la especificación actual, el DaoEmpleado, se deberia hacer esto para conocer el sueldo de un empleado:&lt;/p&gt;        &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; public Long calcularSueldo(Empleado e){&lt;br /&gt;if(e instanceof Administrativo){&lt;/span&gt;&lt;/p&gt;&lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;return(Long)em&lt;br /&gt;.createNamedQuery(“Administrativo.calcularSueldo”)&lt;br /&gt;.setParameter(“administrativo”, e)&lt;br /&gt;.getSingleResult();&lt;/span&gt;&lt;/p&gt;      &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt;}else{&lt;br /&gt;return(Long)em&lt;br /&gt;.createNamedQuery(“Vendedor.calcularSueldo”)&lt;br /&gt;.setParameter(“vendedor”, e)&lt;br /&gt;.getSingleResult();&lt;br /&gt;}&lt;br /&gt;}&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt; &lt;/p&gt; &lt;p style="margin-bottom: 0cm; text-align: justify;"&gt; Nada más lejos de la OOP. Además, el diseño se complicaría mucho más si hay más subclases de Empleado. Con implicit queries, éste metodo no sería necesario, simplemente definiríamos una implicit query por cada subclase de empleado, y la obtención del resultado sería de la siguiente manera:&lt;/p&gt;  &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt; &lt;span style="font-family:Courier New,monospace;"&gt;empleado.getSueldo();&lt;/span&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt; &lt;/p&gt; &lt;p style="margin-bottom: 0cm; text-align: justify;"&gt; Si trasladamos esta característica al ámbito de &lt;b&gt;EJBQL&lt;/b&gt;, la cantidad de consultas anidadas que nos ahorramos es enorme. Por ejemplo, si quisiéramos hallar todos los empleados que tengan un sueldo menor a 3000, tendríamos que anidar una consulta por cada subclase de empleado:&lt;/p&gt;               &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; SELECT DISTINCT(e)&lt;br /&gt;FROM Administrativo a, Vendedores v&lt;br /&gt;WHERE (&lt;br /&gt;a = :empleado AND 3000 &gt; (&lt;br /&gt;SELECT SUM(ht.cantidad)&lt;br /&gt;FROM Administrativo a JOIN a.horasTrabajadas ht&lt;br /&gt;WHERE a = :empleado&lt;br /&gt;)&lt;br /&gt;)OR(&lt;br /&gt;v = :empleado AND 3000 &gt; (&lt;br /&gt;SELECT SUM(venta.comision)&lt;br /&gt;FROM Vendedor v JOIN v.ventas venta&lt;br /&gt;WHERE v = :vendedor&lt;br /&gt;)&lt;/span&gt;&lt;/p&gt;  &lt;p style="margin-bottom: 0cm; color: rgb(0, 102, 0);"&gt;&lt;span style="font-family:Courier New,monospace;"&gt; )&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin-bottom: 0cm; font-family: arial;"&gt;Utilizando Implicit Query, lo anterior se reduce a:&lt;/p&gt;     &lt;p style="margin-bottom: 0cm;"&gt;&lt;span style="color: rgb(0, 102, 0);font-family:Courier New,monospace;" &gt; SELECT e&lt;br /&gt;FROM Empleado e&lt;br /&gt;WHERE e.sueldo &amp;lt; 3000&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;ul&gt;&lt;li&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;b&gt;Simplificación de  expresiones en contextos de Bean:&lt;/b&gt;&lt;/p&gt; &lt;/li&gt;&lt;/ul&gt; &lt;p style="margin-bottom: 0cm; text-align: justify;"&gt; Las implicit queries, al evitar depender de otro objeto para su obtención, simplificarían el acceso a consultas dentro del contexto del Expression Language, porque se podría acceder al resultado navegando por el propio bean.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/35788871-116047523003412459?l=andrestestihispano.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://andrestestihispano.blogspot.com/feeds/116047523003412459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=35788871&amp;postID=116047523003412459' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047523003412459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/35788871/posts/default/116047523003412459'/><link rel='alternate' type='text/html' href='http://andrestestihispano.blogspot.com/2006/10/propuesta-para-consultas-implcitas-en.html' title='Propuesta para Consultas Implícitas en EJB3'/><author><name>Andrés Testi</name><uri>http://www.blogger.com/profile/16389222274573646435</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry></feed>
