tag:blogger.com,1999:blog-17631836413421030442024-03-14T05:10:08.023+01:00Balteustres estrellas alineadasSamuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.comBlogger65125tag:blogger.com,1999:blog-1763183641342103044.post-84293418883708782402013-12-16T09:32:00.000+01:002014-01-07T17:21:23.415+01:002013: A mitad de todo<div style="text-align: right;">
<div style="text-align: left;">
</div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>"A computer is like air conditioning – it becomes useless when you open Windows".</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">-Linus Torvalds</span></div>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Opensource.svg/200px-Opensource.svg.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Opensource.svg/200px-Opensource.svg.png" height="180" width="200" /></a></div>
Como viene siendo ya tradición, en el último post del año doy repaso a algunos acontecimientos interesantes que se han producido.<br />
<br />
Con respecto a JEE, este junio se presentó la nueva especificación JEE 7, justo cuando se cumplen 10 años de la última especificación con el nombre J2EE, la 1.4, tras la cual se redenominó y pasó a llamarse JEE.<br />
<br />
También hay movimientos en cuanto a los servidores de aplicaciones. Mientras Jboss ultima su nuevo Wildfly 8 (no sólo para renombrar Jboss AS sino para evitar confusión y favorecer el mercado a JBoss EAP) Oracle empieza a dar los pasos <a href="http://balteus.blogspot.com.es/2010/12/2010-el-fin-de-una-etapa.html" target="_blank">que me temía</a> tras la compra de Sun Microsystems en 2010, con la decisión de no continuar el soporte comercial de Glassfish a partir del 2014.<br />
<br />
En efecto, los efectos prácticos de la <a href="https://blogs.oracle.com/theaquarium/entry/java_ee_and_glassfish_server" target="_blank">publicación de la actualización del <i>roadmap</i> de Glassfish</a> el pasado Noviembre, según mi lectura, es que en apenas dos años Glasfish dejará de existir tal y como está ahora y volverá a ser el mismo elemento de juguete y testing sobre el que nació.<br />
<br />
Salvo que me equivoque en mi vaticinio, Oracle va a realizarle una jugada perfecta a Red Hat, ya que mucha gente buscará sus alternativas de código abierto (con soporte opcional) en la única alternativa que queda: Wildfly. Supongo que la intención de Oracle es aglomerar tecnología y reducir costes para consolidar su soporte en WLS y forzar a la migración de sus clientes comerciales de Glassfish. Seguramente lo conseguirá en sus clientes actuales, pero no creo que le ayude a conseguir nuevos clientes del segmento medio, donde Red Hat tiene una estrategia clara de comienzo y apoyo en proyectos pequeños y medianos tanto en su nacimiento como en su crecimiento, sin <i>markups</i> altos que puedan suponer un freno.<br />
<br />
En el otro tema de interés del blog, llevamos un diciembre muy interesante de observación en el que podemos ver a un brillante Venus ponerse al Oeste tras el Sol mientras vemos salir también un luminoso Júpiter por el Este que podemos disfrutar durante toda la noche. Unos prismáticos y un trípode son suficientes para que cualquier observador pueda deleitarse con la observación de sus cuatro satélites más visibles (Calisto, Io, Europa y Ganímedes).<br />
<br />
Desgraciadamente, nos hemos perdido un espectáculo que hubiera sido increíble: <a href="http://www.nasa.gov/ison" target="_blank">ISON</a>, de haber sobrevivido, podría haber alcanzado una magnitud de -4,5 y habría sido visible a simple vista en el cielo matutino. Nos conformaremos ahora con recoger muestras del polvo que, en Enero, caerá en nuestro planeta del cometa más observado de la historia.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="https://ytimg.googleusercontent.com/vi/EU-Ef_G1uQg/0.jpg"><param name="movie" value="https://youtube.googleapis.com/v/EU-Ef_G1uQg&source=uds" /><param name="bgcolor" value="#FFFFFF" /><param name="allowFullScreen" value="true" /><embed width="320" height="266" src="https://youtube.googleapis.com/v/EU-Ef_G1uQg&source=uds" type="application/x-shockwave-flash" allowfullscreen="true"></embed></object></div>
<br />
<br />
2013. El primer año con los cuatro dígitos diferentes desde 1987. Un durísimo año en una transición que no termina de producirse. El nuevo año comienza en miércoles, casi a mitad de semana, como una señal de que, en realidad, <b>estamos a mitad de todo y aún a comienzo de nada</b>. En cualquier caso, en lugar de pensar en que queda el resto de semana, prefiero quedarme con la idea de que el lunes y el martes ya han pasado.<br />
<br />
Feliz 2014.<br />
<div>
<br /></div>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-44453698324083843462013-11-29T00:35:00.000+01:002013-12-01T20:51:59.746+01:00JPA: Tips and tricks<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><img border="0" src="http://mrg.bz/MEPoX7" height="200" style="margin-left: auto; margin-right: auto;" width="149" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Photo credit: <a href="http://www.morguefile.com/creative/imelenchon">imelenchon</a></td></tr>
</tbody></table>
<i style="font-family: tahoma;">“Good code is its own best documentation.”</i><br />
<span style="font-family: tahoma;">
</span>
<br />
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">(Steve McConnell)</span></div>
<br />
<br />
<br />
<br />
Cualquiera que lleve varios años desarrollando aplicaciones empresariales Java habrá usado en mayor o menor medida algún ORM para la persistencia en bases de datos de nuestros objetos, dadas las ventajas que aporta al desarrollo y mantenimiento.<br />
<br />
Las enormes ventajas de eficiencia, portabilidad, legibilidad y mantenimiento del código, además de la productividad que aporta evitando escribir fontanería manual de serialización/deserialización de datos a objetos lo hacen prácticamente imprescindible en cualquier proyecto que acceda a bases de datos. Sin embargo, me he encontrado con casos donde hay que usar elementos no portables de JPA o, directamente, no usar JPA en absoluto. El rendimiento suele ser la razón fundamental y más frecuente, pero hay otras, como la legibilidad y mantenibilidad o simplemente, la sencillez. Son los siguientes casos:<br />
<div>
<ul>
</ul>
</div>
<div>
<ul>
<li><u>Tratamiento o movimiento de datos masivo</u> (grandes transacciones con operaciones de inserción, actualización o borrado). En estos casos, realizarlo a través de los objetos o vía JPQL no es eficiente. Es mejor realizar consultas nativas (NativeQuery) o funciones/procedimientos almacenados.</li>
<li><u>JPQL ineficiente</u>. Hay casos donde, por ejemplo, un OUTER JOIN con JPQL no realiza lo que queremos. Además, no existe (al menos yo no conozco ninguno, se agradecen aportaciones ;-) ningún cliente JPQL que nos permita probar y testar consultas JPQL con lo que realizar consultas complejas en JPQL es una tarea tremendamente ardua y pesada. En estos casos, las consultas se crean y prueban en SQL nativo y se implementan como tales.</li>
<li><u>Presentación de datos tabulares estadísticos o calculados con sumatorios, agregados, agrupados, etc...</u>. Hay veces que se necesita una tabla (normalmente de cálculo) producto de una consulta compleja que no coincide con nuestro modelo de datos. En estos casos la "fontanería" con objetos es ilegible o directamente intratable.</li>
</ul>
No hay que complicarse en exceso y usar el <a href="http://en.wikipedia.org/wiki/KISS_principle" target="_blank">principio KISS</a>. Si el problema se puede solucionar de forma sencilla, elegante y eficiente usando SQL nativo o funciones almacenadas, el "purismo" de la portabilidad no puede llevarse al extremo de realizar una aplicación ineficiente o inmantenible.</div>
<div>
<br /></div>
<div>
Dicho esto, mi recomendación es usar JPA por defecto en cualquier proyecto que trabaje con bases de datos y plantearse usar SQL nativo o funciones almacenadas exclusivamente en los casos estrictamente necesarios en los que el rendimiento, la mantenibilidad, legibilidad o simpleza así lo aconsejen.<br />
<br />
En mi experiencia usando JPA 1.0 (Toplink Essentials) y JPA 2.0 (EclipseLink) en diversos proyectos he recopilado los siguientes <b>consejos prácticos, trucos y advertencias</b> que suelo tener en cuenta y que voy a compartir aquí:<br />
<br />
<h2>
<span style="color: #45818e;">
<span style="color: #0b5394;">1.- NamedQuerys en fichero orm.xml (y no como anotaciones en las <i>entidades</i>)</span></span></h2>
Aunque la especificación JPA enfatiza el uso de anotaciones, puedes usar el fichero de mapeo JPA orm.xml para almacenar los metadatos. Aunque el uso de anotaciones o descriptores XML es una cuestión de gustos, considero especialmente útil usar descriptores XML cuando nos apoyamos en wizards y herramientas de generación de código (como <a href="http://www.eclipse.org/webtools/dali/" target="_blank">Dali</a>), ya que éstas suelen sobreescribir nuestros ficheros de entidad perdiendo así todas nuestras NamedQuerys. Almacenar las NamedQuery en el fichero orm.xml nos permitirá no perderlas cuando Dali o cualquier otro generador de código sobreescriba nuestras entidades.<br />
<br />
Es decir, en lugar de ésto en nuestras entidades:<br />
<pre class="brush:java; gutter: false;" font-size="x-small">@NamedQueries( {
@NamedQuery(name = "Profile.findAll",
query = "SELECT o FROM Profile o ORDER BY o.name"),
@NamedQuery(name = "Profile.findByName",
query = "SELECT o FROM Profile o WHERE UPPER(o.name) LIKE :name ORDER BY o.name")
})
</pre>
<br />
Escribirlo en el fichero orm.xml:<br />
<pre class="brush:xml; gutter: false;" font-size="x-small"><entity-mappings version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/persistence/orm" xsi:schemalocation="http://java.sun.com/xml/ns/persistence/orm
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">
<persistence-unit-metadata>
<persistence-unit-defaults>
<access>PROPERTY</access>
</persistence-unit-defaults>
</persistence-unit-metadata>
<named-query name="Tag.findNotAdded">
<query><![CDATA[SELECT o FROM Tag o INNER JOIN o.tagProfiles tp
WHERE tp.profile <> :profile ORDER BY o.name]]></query>
</named-query>
<named-query name="Profile.findAll">
<query><![CDATA[SELECT o FROM Profile o ORDER BY o.name]]></query>
</named-query>
<named-query name="Profile.findByName">
<query><![CDATA[SELECT o FROM Profile o WHERE UPPER(o.name) LIKE :name ORDER BY o.name]]></query>
</named-query>
</entity-mappings></pre>
<br />
<br />
<h2>
<span style="color: #0b5394;">
2.- Obtener objetos manejados y sincronizados</span></h2>
<div>
Es posible que te hayas encontrado en algún momento con errores del tipo:<br />
<br />
<span style="font-family: Courier New, Courier, monospace; font-size: x-small;">java.lang.IllegalArgumentException: Entity must be managed to call remove: __MiObjeto__, try merging the detached and try the remove again.</span></div>
<div>
<br /></div>
<div>
La caché de entidades de JPA es manejada por el framework internamente. Es posible que un entity de tu aplicación, que recuperaste vía em.find() o JPQL, ya no esté en dicha caché porque haya sido reciclado (aunque en tu código apenas "hayan pasado" un par de llamadas de métodos o un par de líneas de código ;-). En estos casos es cuando te encuentras con el primer error, por ejemplo, si llamas a EntityManager.remove() de un objeto "detached".<br />
<br />
Una solución que se te puede ocurrir es usar EntityManager.refresh() para "refrescar" el objeto y sincronizarlo con la base de datos, es decir: para hacerlo "manejado" nuevamente... Pero te puedes encontrar con otro error:<br />
<br />
<span style="background-color: white; font-family: 'Courier New', Courier, monospace; font-size: 14px; line-height: 18px;">refresh() cannot be called on a detached entity</span><br />
<br />
<br />
Para asegurarte que tienes un objeto "manejado" y, en cualquier caso, para estar seguro que puedes modificar un objeto sincronizado con la base de datos, una la combinación de find() y refresh() siguiente:<br />
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">Usuario e = em.find(Usuario.class, id);
try {
em.refresh(e);
} catch( EntityNotFoundException ex ) {
e = null;
}
</pre>
<br />
<h2>
<span style="color: #0b5394;">3.- Uso de callbacks. El caso especial de la anotación @PreUpdate</span></h2>
Las anotaciones @Pre* y @Post* para <i>callbacks methods</i> tienen una utilidad ciertamente limitada. De hecho, no hay más que leer la sección 3.5 de la especificación JPA:<br />
<blockquote class="tr_bq">
“In general, the lifecycle method of a portable application should not invoke EntityManager or Query operations, access other entity instances, or modify relationships within the same persistence context. A lifecycle callback method may modify the non-relationship state of the entity on which it is invoked.”</blockquote>
<br />
Existen razones técnicas de peso para lo anterior (por ejemplo, evitar bucles infinitos que pueden dar al traste con una aplicación), pero desde el punto de vista del desarrollo está muy lejos de constituir un equivalente a los disparadores en la base de datos, ya que sólo podemos trabajar con la propia entidad, e incluso, con restricciones, como ahora veremos.<br />
<br />
La anotación @PrePersist nos permite establecer un estado en una entidad antes de que ésta sea persistida. ¿Funciona igual @PreUpdate? Vamos a verlo.<br />
<br />
Imaginemos que tenemos una entidad con un campo campoDato que, cuando se modifica, debe tener su fecha correspondiente de modificación en su campo aparejado fechaCampoDato. Para olvidarnos de éste último, podríamos tener la tentación de hacer algo como esto:<br />
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">@PrePersist
@PreUpdate
public void preUpdate() {
if ( campoDato != null) {
// Si tiene campoDato, hay que garantizar su fecha también
if ( fechaCampoDato == null) {
fechaCampoDato = new Date();
}
}
}</pre>
<br />
Sin embargo, <u>no funciona</u> (al menos en EclipseLink) ¿Por qué? Porque para la verificación de modificación ("<i>dirty check")</i>, los campos modificados son detectados <u>antes</u> de llamar al método @PreUpdate y, por tanto, los cambios realizados en el método @PreUpdate no son detectados. Nuevamente, esto está realizado así por razones de rendimiento debido a que las verificaciones de modificación son muy costosas.<br />
<br />
En definitiva, los métodos <i>callback</i> no son la panacea en lo referente a la gestión del ciclo de vida de nuestras entidades.<br />
<br />
<h2>
<span style="color: #0b5394;">4.- ¿JPQL demasiado lenta?</span></h2>
Cuando tenemos un modelo complejo con muchas relaciones, algunas ejecuciones de JPQL en el que muchas entidades se vean involucradas (muchos JOIN) pueden resultar inaceptablemente lentas. Especialmente cuando nos percatamos que la consulta nativa SQL equivalente apenas lleva unos pocos milisegundos. En estos casos, optamos por realizar una consulta nativa SQL ( <i><a href="http://docs.oracle.com/javaee/6/api/javax/persistence/EntityManager.html#createNativeQuery(java.lang.String,%20java.lang.Class)" target="_blank">createNativeQuery(java.lang.String sqlString,java.lang.Class resultClass)</a></i> ) obteniendo también un rendimiento lamentable, cuando la misma consulta SQL se ejecuta centenas de veces más rápido en nuestro cliente SQL. ¿Qué está pasando? ¿Cómo solucionarlo?<br />
<br />
En estos casos el problema no es la consulta: es el propio JPA, o más concretamente, la resolución de entidades de JPA. Cuando se usan NamedQuery o entity-mapped-nativequery (es decir, nativas usando mapping "automático" a la entidad de retorno), JPA realiza la consulta y mapeo de las entidades devueltas, resolviendo en éstas las relaciones involucradas en la consulta. Es decir, que si tengo una entidad con varias relaciones, resuelve las listas de estas relaciones, generando una cantidad de consultas enorme y consumiendo, por tanto, muchísimo tiempo.<br />
<br />
La solución para estos casos es simple: realizar una consulta nativa que devuelva los identificadores de las entidades en lugar de las entidades, para luego resolver las entidades manualmente. Por ejemplo:<br />
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">public List<User> getUserByProfile(Integer profileId) {
List<Vector> rows = null;
List<User> users = new ArrayList<User>();
String query;
try {
query = "select distinct t1.id " +
" from t1,t2,t3,t4,t5" +
" where t1.f1_id = t2.id" +
" and t2.f2_id = t3.id" +
" and t4.f4_id = t5.id" +
" and t5.id = " +
" and t2.end_date is null" +
" and exists (select * from a " +
" where date is null and h = t5.id)" +
" and t5.id = "+ profileId;
Query q = em.createNativeQuery(query);
log.debug("query {}", query);
rows = q.getResultList();
for ( Vector row : rows ) {
users.add(em.find(User.class, (User)row.get(0)) );
}
return users;
} catch (Exception e) {
log.error("Excepcion ", e);
}
}
</pre>
<br />
Podrás comprobar que la solución anterior, aún siendo poco "<i>bonita</i>" y más tediosa, es centenares de veces más rápida que dejar a JPA que resuelva las entidades. La razón es muy sencilla: con esta forma, no se resuelven innecesariamente las relaciones de las tablas en la consulta.<br />
<br />
<h2>
<span style="color: #0b5394;">4.- @PrivateOwned o tratamiento de huérfanos</span></h2>
Es frecuente confundir el atributo cascade y pensar que éste se encarga de todo. Pero no es así. Si tenemos una relación @OneToMany(cascade=ALL) y borramos el padre, sus hijos también se eliminarán. Pero, ¿y si queremos borrar alguna entidad hija? Si tenemos un objeto A que tiene una lista de objetos B hijos y borramos el segundo, de la lista (usando remove()), una llamada a merge() no eliminará el objeto dereferenciado. ¿Por qué? Porque el objeto sigue siendo una entidad que no ha sido explícitamente eliminada. Hemos borrado una referencia a él, pero no la única y, en todo caso, el objeto sigue manteniendo la referencia a su padre.<br />
<br />
Muchas veces nos encontramos la definición del atributo @PrivateOwned así: "Use @PrivateOwned to specify that a relationship is privately owned"... lo cual obviamente, no aclara mucho. Lo voy a explicar aquí un poco más claro: @PrivateOwned implica que los hijos pertenecientes a la lista no deben existir sin el padre, con lo que, al quedar dereferenciados, deberán ser eliminados. Podrás usar este atributo para buena parte de las relaciones @OneToMany cuyos hijos tengan una dependencia funcional absoluta del padre y en las que normalmente trabajarás con el objeto padre como una unidad única y no con los hijos de forma independiente. Es decir, en aquellas donde un objeto hijo "huérfano" no tiene sentido.<br />
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">@OneToMany(mappedBy = "padre", cascade={CascadeType.ALL})
@PrivateOwned
private List<Hijo> hijos;
</pre>
<br />
Con JPA 1.0, los objetos hijos "huérfanos" deben eliminarse explícitamente con em.remove() ya que este atributo sólo está disponible para JPA 2.0.<br />
<br />
<h2>
<span style="color: #0b5394;">5.- Logging </span></h2>
Durante el ciclo de desarrollo, es una buena idea activar el logging de las sentencias SQL que nuestro proveedor de JPA realiza en tiempo de ejecución, para tener visibilidad de qué está ocurriendo en cada momento. En EclipseLink, se configura a través de una propiedad en el fichero persistence.xml.<br />
<br />
<pre class="brush:xml; gutter: false;" font-size="x-small"><properties>
<property name="eclipselink.logging.level" value="FINE"/>
</properties>
</pre>
<br />
<br />
<h2>
<span style="color: #0b5394;">6.- JPA Caching</span></h2>
La caché de nivel 2, <i>L2</i> o s<i>hared</i> cache, es una caché más allá del <i>EntityManager</i>: es una caché global para toda la unidad de persistencia (<i>PersistenceUnit</i>). En general, la caché es un elemento importante y complejo cuya correcta configuración puede tener un significativo impacto en nuestra aplicación. Explicar estos detalles excede el alcance de este artículo y hay mucha información ya publicada al respecto. No obstante, expondré aquí mi experiencia con TopLink (JPA 1.0) y EclipseLink (JPA 2.0)<br />
<br />
<h3>
JPA 1.0</h3>
Mi experiencia con Toplink Essentials es que es conveniente desactivar la shared cache, salvo que la base de datos no tenga modificaciones externas simultáneamente a nuestra aplicación (otras aplicaciones, etc), lo cual no suele ocurrir (en mi caso, nunca). Así que, como norma general, la opción habitual es configurarlo en el persistence.xml:<br />
<br />
<pre class="brush:xml; gutter: false;" font-size="x-small"><properties>
<property name="toplink.cache.shared.default" value="false"/>
</properties> </pre>
<br />
<h3>
JPA 2.0</h3>
EclipseLink ofrece mayores niveles de configuración y ajuste que permiten una configuración más fina y granulada, aunque aún me quedan por probar el comportamiento en producción de muchas opciones. De momento, una buena opción es desactivar la shared cache para todas las entidades y permitir sobreescribir esta configuración para entidades concretas vía orm.xml o anotación @Cacheable en función de nuestra aplicación.<br />
<br />
<pre class="brush:xml; gutter: false;" font-size="x-small"><properties>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
</properties>
</pre>
<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://en.wikibooks.org/wiki/Java_Persistence/Caching" target="_blank">Java Persistence / Caching</a></li>
<li><a href="http://www.eclipse.org/eclipselink/documentation/2.5/concepts/cache.htm" target="_blank">EclipseLink: Understanding Caching</a> </li>
<li><a href="http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Configuring" target="_blank">EclipseLink: Configuring Caching</a> </li>
</ul>
<br />
<ul>
</ul>
</div>
</div>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com2tag:blogger.com,1999:blog-1763183641342103044.post-84565460876858336132013-09-29T13:16:00.002+02:002013-10-02T22:34:49.922+02:00Migrando a JEE 6 / EJB 3.1 (II)<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_LI5LA48LcCrq6RgWOQSYnvxSJL2qSblHzdkESIVz7UJ1420Kqs1JRkgA0JG-Yp7MDWioErrL9tMum9zN346kwQa9j1nX6rJw9RRDJ6DEd3JyXXwacKwJqS4LetP2I3eXqSp-UBtB8iQ/s1600/coffee_t.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_LI5LA48LcCrq6RgWOQSYnvxSJL2qSblHzdkESIVz7UJ1420Kqs1JRkgA0JG-Yp7MDWioErrL9tMum9zN346kwQa9j1nX6rJw9RRDJ6DEd3JyXXwacKwJqS4LetP2I3eXqSp-UBtB8iQ/s200/coffee_t.png" width="200" /></a></div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>“A programmer is a person who passes as an exacting expert on the basis of being able to turn out, after innumerable punching, an infinite series of incomprehensive answers calculated with micrometric precisions from vague assumptions based on debatable figures taken from inconclusive documents and carried out on instruments of problematical accuracy by persons of dubious reliability and questionable mentality for the avowed purpose of annoying and confounding a hopelessly defenseless department that was unfortunate enough to ask for the information in the first place.”
</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">(IEEE Grid newsmagazine)</span></div>
<br />
En esta segunda parte de esta serie (podéis ver la primera parte <a href="http://balteus.blogspot.com/2012/06/migrando-jee-6-ejb-31-i.html">aquí</a>) comentaré mi experiencia con el famoso nuevo sistema estandarizado o único de nombres JNDI (<i>portable JNDI names</i>).<br />
<br />
<div>
Tras varias aplicaciones, he llegado a una nomenclatura que me ha parecido adecuada para el nombrado de mis objetos y recursos siguiendo mi propio estándar.:<br />
<br />
<br />
<ol>
<li>Declaración de EJB: defino un nombre de aplicación y declaro todos los ejb con la nomenclatura general "global" usando dicho nombre:</li>
@EJB(name="java:global/nombre_aplicacion/nombre_ejb",
beanInterface=nombre_ejb_interfaz_local.class)
<li>Acceso a referencias de EJB locales: la declaración la hago usando siempre:</li>
<pre class="brush:java; gutter: false;" font-size="x-small">@EJB(name="java:module/nombre_ejb")</pre>
<li>Acceso a referencias locales de EJB desde otros módulos: usando la nomenclatura </li>
<div>
<pre class="brush:java; gutter: false;" font-size="x-small">java:global/nombre_ejb</pre>
</div>
<li>Acceso a recursos: igual que antes, pero usando "lookup" en lugar de "mappedName" en la notación @Resource</li>
</ol>
<br />
<br />
A continuación muestro ejemplos de cómo cambia la declaración de elementos con EJB 3 (JEE5) a EJB 3.1 (JEE6).</div>
<div>
<br /></div>
<table border="1" cellpadding="5" with="600">
<thead>
<tr>
<th></th>
<th width="300px">con EJB 3 (JEE5)</th>
<th width="300px">con EJB 3.1 (JEE6)</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>Declaración</b></td>
<td><pre class="brush:java; gutter: false;" font-size="x-small">@Stateless(name="BalteusService",
mappedName="ejb/BalteusService")
public class BalteusService;</pre>
</td>
<td><pre class="brush:java; gutter: false;" font-size="x-small">@Stateless()
@EJB(name="java:global/BalteusApp/BalteusService",
beanInterface=BalteusServiceLocal.class)
</pre>
</td></tr>
<tr>
<td><b>EJB Ref</b></td>
<td><pre class="brush:java; gutter: false;" font-size="x-small">@EJB
private OtherServiceLocal otherService</pre>
</td>
<td><pre class="brush:java; gutter: false;" font-size="x-small">@EJB(name="java:module/OtherService")
private OtherServiceLocal otherService</pre>
</td></tr>
<tr>
<td><b>Resource Ref</b></td>
<td><pre class="brush:java; gutter: false;" font-size="x-small">@Resource(mappedName="jdbc/BalteusDS")
private DataSource BalteusDS;</pre>
</td>
<td><pre class="brush:java; gutter: false;" font-size="x-small"> @Resource(lookup="jdbc/BalteusDS")
private DataSource BalteusDS;</pre>
</td></tr>
</tbody></table>
<div>
<br /></div>
<div>
Para la utilización de interfacez locales de EJB desde otros módulos de un EAR (por ejemplo, desde una aplicación web), donde antes usaba el típico patrón ServiceLocator, ahora uso una adaptación del patron BeanLocator (que es una especie de ServiceLocator 2.0), descrito por Adam Bien en su libro (<a href="http://www.adam-bien.com/roller/abien/entry/ejb_3_1_beanlocator_when">http://www.adam-bien.com/roller/abien/entry/ejb_3_1_beanlocator_when</a>).<br />
<br />
La forma de utilizar el patrón </div>
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">/**
public class BeanLocator {
* Para realizar el lookup de interfaces locales
*
* Asume que los servicios están declarados como "java:global/XXXService"
* (p.e. @EJB(name="java:global/UserService",beanInterface=UserServiceLocal.class) ), es decir,
* asume que el nombre JNDI declarado es el nombre de la interfaz eliminando el sufijo "Local"
* @param clazz
* @return
*/
public static <T> T lookup(Class<T> clazz) {
String name = clazz.getSimpleName();
return lookup(clazz,"java:global/cestelJEEApp/" + name.substring(0, name.indexOf("Local")));
}
}
</pre>
<br />
Con este BeanLocator, obtener una referencia a la interfaz local, es algo muy sencillo. Por ejemplo:<br />
<br />
<pre class="brush:java; gutter: false;" font-size="x-small">PaisServiceLocal paisService = BeanLocator.lookup(PaisServiceLocal.class);
</pre>
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://balteus.blogspot.com/2012/06/migrando-jee-6-ejb-31-i.html">Migrando a JEE 6 / EJB 3.1 (I)</a></li>
<li><a href="http://glassfish.java.net/javaee5/ejb/EJB_FAQ.html">EJB FAQ</a></li>
<li><a href="http://www.adam-bien.com/roller/abien/entry/ejb_3_1_beanlocator_when" target="_blank">EJB 3.1 BEANLOCATOR - WHEN DEPENDENCY INJECTION IS NOT ENOUGH</a></li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-51260685838001972302013-03-06T01:45:00.003+01:002013-03-18T22:58:08.754+01:00...Y cuatro<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDc-Yy6yWUYE_epwO8MTSngoIuGiF3O1f5JAws8V8pdSYxsTs_6vbIdj9CJjocjswUiS9i0VXLFsYTx787ma0u7KwvUzbLyFFykO0SHxxsT0nfWF6WxVo3v-VOBPY44cQMH7sLKgM6ryE/s1600/blade_runner6.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiDc-Yy6yWUYE_epwO8MTSngoIuGiF3O1f5JAws8V8pdSYxsTs_6vbIdj9CJjocjswUiS9i0VXLFsYTx787ma0u7KwvUzbLyFFykO0SHxxsT0nfWF6WxVo3v-VOBPY44cQMH7sLKgM6ryE/s320/blade_runner6.jpeg" width="320" /></a></div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>"No sé por qué me salvó la vida. Quizá en esos últimos años él amó la vida con más intensidad que nunca, no sólo su vida, la de cualquiera, mi vida. Y lo único que quería eran las mismas respuestas que el resto de nosotros: ¿de dónde vengo?, ¿a dónde voy?, ¿cuánto tiempo me queda? Todo lo que podía hacer era quedarme allí y verlo morir"</i>- Deckard</span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Blade Runner</span></div>
<br />
<br />
Hoy este blog cumple su cuarto año en la que probablemente sea la situación socio-económico-política más difícil de la gente de mi generación. Es difícil apartar el contexto en el que este blog se publica y evitar la tentación de escribir algo sobre la crisis y la actualidad. Y aunque este blog tiene y seguirá teniendo una temática exclusivamente técnica (o tecnológico-científica, si incluyo los temas de astronomía y actualidad tecnológica) es inevitable que se impregne del desánimo y la indignación social en la que vivimos.<br />
<br />
Quizá por ello he querido (<a href="http://balteus.blogspot.com.es/2012/03/balteus-cumple-su-tercer-ano.html" target="_blank">una vez más</a>) traer aquí la secuencia final de Blade Runner, invocando la misma catarsis y perplejidad existencial que provocaba en Deckard... y probablemente aguardando la renovación que se supone que esperamos y deseamos muchos.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPM9l3s4S2_6jH3ye2EuCtee4WIg9C6QRjAf3NiQoktv6rTNaNjNgFanX7fsWKgklX6QdZXzE58uZ0_jXVeYwCD_0OIOlDmm-nlmxfInY9Y1QwtjdsH5gWoCaKsFOzRRQMcQ3lnWxQukI/s1600/balteus4.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPM9l3s4S2_6jH3ye2EuCtee4WIg9C6QRjAf3NiQoktv6rTNaNjNgFanX7fsWKgklX6QdZXzE58uZ0_jXVeYwCD_0OIOlDmm-nlmxfInY9Y1QwtjdsH5gWoCaKsFOzRRQMcQ3lnWxQukI/s200/balteus4.jpg" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">2013 (C) Fran Barquero</td></tr>
</tbody></table>
<br />
Gracias, Fran, por la ilustración de aniversario de este Blog.<br />
<br />
Saludos y gracias por tu visita.<br />
<br />
<br />Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-29392310066441619272013-02-15T13:03:00.002+01:002013-02-15T13:05:39.240+01:00Error del instalador Unix de glassfish 3.1.2.2<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivZgr5eok9aNIj5aweyuJvOIMcQTQibcfaymFrJNC8lJZHqidifP1RDq62BKrKEf7Z8DoH6iksqEWez4UoLUlsf_zYejFSUa79fkCupcdo-xfCz0jqkSJibuPBvkXnqHeeUxht-x8J2mw/s1600/sparky_v3_blue.gif" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivZgr5eok9aNIj5aweyuJvOIMcQTQibcfaymFrJNC8lJZHqidifP1RDq62BKrKEf7Z8DoH6iksqEWez4UoLUlsf_zYejFSUa79fkCupcdo-xfCz0jqkSJibuPBvkXnqHeeUxht-x8J2mw/s1600/sparky_v3_blue.gif" /></a></div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>A la vista de suficientes ojos, todos los errores resultan evidentes.</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;"><a href="http://es.wikipedia.org/wiki/Ley_de_Linus">Ley de Linus</a>, formulada por Linus Torvalds, (1997).</span></div>
<br />
Si has instalado<b> Glassfish 3.1.2.2 en un servidor Unix en español y has seleccionado "Instalación personalizada"</b>, habrás sufrido el extraño error:<br />
<br />
<pre class="brush:text; gutter: false;">org.jdom.input.JDOMParseException: Error on line 98: El tipo de elemento "htmlpanel"
debe ir seguido de una de estas especificaciones de atributo: ">" o "/>".
WARNING: No se ha podido procesar un evento de navegación para
command=AC_NEXT [Comando=AC_NEXT Error=Invalid SwiXML Descriptor. ]
</pre>
<br />
La interfaz gŕafica presenta una imagen como la siguiente:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQExPZYv3_TDuoP5trPVKcRFPIhfnzmDRhBkCXclnxAM2QFN_MLPtnXQfMVBj1KFNC5G0Z-sYlJ5T4AMFLi19SSdMGPe6wvJlbt8RBrwIEK051zHijPPKt1vDzr7OLMqb-J4VZdzsI-Cg/s1600/instant%C3%A1nea1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="491" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQExPZYv3_TDuoP5trPVKcRFPIhfnzmDRhBkCXclnxAM2QFN_MLPtnXQfMVBj1KFNC5G0Z-sYlJ5T4AMFLi19SSdMGPe6wvJlbt8RBrwIEK051zHijPPKt1vDzr7OLMqb-J4VZdzsI-Cg/s640/instant%C3%A1nea1.png" width="640" /></a></div>
<br />
Tal y como me imaginé, tiene que ver con el poco cuidado que está teniendo Oracle con los idiomas últimamente en los instaladores (el instalador de la versión 3.1 también adolecía de similares problemas). La solución es muy sencilla: ejecutar el instalador forzando el idioma inglés, por ejemplo, así:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>szarza@szarza:~$ LANG=EN ./glassfish-3.1.2.2-unix.sh
</b></span><br />
<br />
con lo que podremos acceder a la instalación personalizada sin problemas.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxZbUmPXuNUVR4DboMy-1bLMQ7mIF7wq6CSBqeWjducxkG7o_YX9_z-qx31N0mfyh1IExZ7nNLvQWrL7kMwjYoYJDE5THom_Hq3dTVnZZzwFZOoVzuM-8j8TG-6A-qK4bAliuHJi9je_w/s1600/instant%C3%A1nea2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxZbUmPXuNUVR4DboMy-1bLMQ7mIF7wq6CSBqeWjducxkG7o_YX9_z-qx31N0mfyh1IExZ7nNLvQWrL7kMwjYoYJDE5THom_Hq3dTVnZZzwFZOoVzuM-8j8TG-6A-qK4bAliuHJi9je_w/s640/instant%C3%A1nea2.png" width="640" /></a></div>
<br />
<br />
Supongo que existe algún error en los XML del instalador con recursos en español que no se escapan debidamente.<br />
<br />
Espero que os ayude en casos similares.Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com10tag:blogger.com,1999:blog-1763183641342103044.post-58461164690415760572012-12-14T01:27:00.000+01:002013-01-04T00:53:46.455+01:002012: El fin de los magufos<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70vLY93nmUO961bgJMTOX9ajNJFARN-RgN9Y_R4lo2H-4pe1k9Z5uQVrp1TayokCMnjp78nuDFc9sRtbwvjceDahZVrhAzQwsUsYEwCqYiDZJ-Iqk-WCr73Uokl3fcsM0pLPT57NtlF8/s1600/133px-La_Mojarra_Inscription_and_Long_Count_date.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70vLY93nmUO961bgJMTOX9ajNJFARN-RgN9Y_R4lo2H-4pe1k9Z5uQVrp1TayokCMnjp78nuDFc9sRtbwvjceDahZVrhAzQwsUsYEwCqYiDZJ-Iqk-WCr73Uokl3fcsM0pLPT57NtlF8/s1600/133px-La_Mojarra_Inscription_and_Long_Count_date.jpg" /></a></div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>“Windows NT addresses 2 Gigabytes of RAM, which is more than any application will ever need.”</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">
(Microsoft, on the development of Windows NT, 1992)</span></div>
<br />
Este año que termina es el año favorito de los <a href="http://blogs.elcorreo.com/magonia/2007/02/20/magufo-la-wikipedia/" target="_blank">magufos</a>. Tras las bobadas del fallido fin del mundo del año 2000, llega el siguiente fin del mundo: el 21 de Diciembre de 2012. Ya veremos cuando será el próximo...<br />
<br />
Ayer se me ocurrió escribir sobre esto pensando en el pasado 12-12-12, al que se le atribuyeron no pocas insensateces cuando todo el mundo sabe que lo único importante de ese día es que es el cumpleaños de uno de mis hermanos. Con las <strike>profecías</strike> chorradas de Nostradamus ya cubiertas de polvo, a los charlatanes cuentistas y demás inventores de tonterías, les dió por mirar, mira tú, nada más y nada menos que a uno de los <a href="http://es.wikipedia.org/wiki/Cuenta_larga" target="_blank">calendarios Maya</a>... ¡Y dio hasta para una <a href="http://es.wikipedia.org/wiki/2012_(pel%C3%ADcula)" target="_blank">película</a>!<br />
<br />
En fin. Queridos lectores, lamento ser yo quien os fastidie el magno espectáculo, pero el 21 de diciembre de 2012 a las 11:12 UTC no va a ser el fin del mundo. Ocurrirá lo que todos los años en torno al mismo momento aproximadamente: el solsticio. El universo no se rige por nuestras formas de contar las cosas. La verdad es que el fin del mundo será un impresionante espectáculo, pero aún nadie sabe cuando sucederá porque, obviamente, no depende de ningún adivinador. No hay problema. La humanidad tiene butacas reservadas para ese espectáculo. Y es seguro que sucederá antes de los próximos 3.000 millones de años... Me apuesto una cena. En todo caso, a los engañabobos les quedará el refugio del próximo año, un 13, que dará para más bobadas que ayuden a sus ingenuos cŕedulos a olvidar sus "predicciones" anteriores.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
En medio de esta agitada crisis, la comunidad científica nos regaló este año con el que probablemente será el primer descubrimiento más significativo de este siglo: una nueva partícula que concuerda con el bosón de Higgs. Si se confirma el descubrimiento de la maldita partícula ("<i>The goddamn particle</i>", no the <i>"God Particle"</i>, como el editor de <a href="http://en.wikipedia.org/wiki/Leon_M._Lederman" target="_blank">Leon Lederman</a> transformó con disparatado desatino), la física podría corroborar el modelo estándar en los próximos años o, en todo caso, permitirá extraordinarios avances en física.<br />
<br />
Más prosaico pero no menos importante: <a href="http://es.wikipedia.org/wiki/Blade_Runner" target="_blank">Blade Runner</a> cumple su 30 aniversario este año. Ya conocen mis lectores habituales <a href="http://balteus.blogspot.com.es/2012/03/balteus-cumple-su-tercer-ano.html" target="_blank">mi devoción por esa película</a>.<br />
<br />
Este segundo semestre del año mi actividad en el blog ha sido muy poca por razones diversas que no vienen a cuento ahora, pero soy consciente de ello. Y es que este año está siendo francamente difícil para mi en términos de tiempo libre para el blog (y también en otros que tampoco vienen al caso ahora).<br />
<br />
<b id="internal-source-marker_0.6587561157066375" style="font-weight: normal;">Con suerte, el 21 de Diciembre se podrían acabar las magufadas de una vez por todas, aplastadas por la tozuda y sencilla realidad... pero no se debería a los mayas, sino al uso de nuestro cerebro con la mejor de las herramientas: el pensamiento científico... y a falta de ello, el sentido común.</b><br />
<b style="font-weight: normal;"><br /></b>
<b style="font-weight: normal;">A por el 13!!</b><br />
<b style="font-weight: normal;"><br /></b><b style="font-weight: normal;">Feliz año nuevo.</b><br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><span style="color: #0000ee;"><a href="http://blogs.elcorreo.com/magonia/2007/02/20/magufo-la-wikipedia/" target="_blank">Magufo</a></span></li>
<li><span style="color: #0000ee;"><u><a href="http://lacienciaysusdemonios.com/2010/03/23/10-frases-que-jamas-entraran-la-cabeza-de-un-magufo/" target="_blank">10 frases que jamás entrarán en la cabeza de un magufo</a></u></span></li>
<li><span style="color: #0000ee;"><u><a href="http://lacienciaysusdemonios.com/2010/02/19/cinco-caracteristicas-fundamentales-del-vendedor-de-humo" target="_blank">Cinco características fundamentales del vendedor de humo</a></u></span></li>
<li><span style="color: #0000ee;"><a href="http://naukas.com/categorias/escepticismo/alerta-magufo/" target="_blank">Naukas: Alerta Magufo</a></span></li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-8306528777539973912012-10-17T01:31:00.002+02:002013-06-13T10:00:25.686+02:00Comparar y actualizar esquemas de PostgreSQL<div style="text-align: right;">
<div style="text-align: left;">
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQMB-zd9qgXt7gfDj_eMMpXgGXNKG_lQx_lyuQFrfJOcuFSqATfNvwpXs58kFqQ9NElWoM7be_vwnt32Bp3Ikqhli-gsYU3TrrZ6RxOOdUIliNgbv0vkfPvqfGZ96wa_COKnu27jhUBw/s1600/database-schema.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="160" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjzQMB-zd9qgXt7gfDj_eMMpXgGXNKG_lQx_lyuQFrfJOcuFSqATfNvwpXs58kFqQ9NElWoM7be_vwnt32Bp3Ikqhli-gsYU3TrrZ6RxOOdUIliNgbv0vkfPvqfGZ96wa_COKnu27jhUBw/s320/database-schema.jpg" width="320" /></a></div>
</div>
<span style="font-family: tahoma;">
</span>
<br />
<blockquote>
<span style="font-family: tahoma;"><i>"1f y0u c4n r34d 7h15, y0u r34||y n33d 70 637 41d."</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;"><a href="http://en.wikipedia.org/wiki/Leet">1337</a></span></div>
<br />
Al pasar a producción nuevas versiones de software empresarial necesitamos automatizar la "actualización" del sistema con el objeto de que sea repetible y pueda realizarse lo más rápidamente posible y sin errores. Uno de los elementos críticos es el esquema de nuestra base de datos sobre el cual, en la mayor parte de los casos, descansa la estructura vertebral de nuestro sistema.<br />
<br />
Si la comparación y obtención de diferencias (comparison/diffing) entre el esquema antiguo y el nuevo es una tarea tediosa que está sujeta a numerosos errores, la generación de un script SQL de actualización es aún más compleja, ya que requiere un tratamiento inteligente y ordenado de dichas diferencias.<br />
<br />
Para ayudarnos en esta tarea con PostgreSQL, me encontré una excelente herramienta: <a href="http://apgdiff.startnet.biz/" target="_blank">A<span id="goog_1331275000"></span>nother PostgreSQL Diff Tool (apgdiff)</a><a href="http://draft.blogger.com/"><span id="goog_1331275001"></span></a>. <b>Agpdiff</b> es una herramienta <b>gratuita</b> de comparación y obtención de diferencias de esquemas de bases de datos (database schema diff tool) específica para PostgreSQL. La he probado y he de decir que quedé realmente impresionado. Tan sólo tuve que añadir las lógicas modificaciones al script de actualización generado relacionadas con los datos (actualización de filas con valores NULL en campos que pasan a ser NOT NULL, etc...).<br />
<br />
En el sitio de la herramienta viene información suficiente sobre su funcionamiento y cómo usarlo. Sólo añadir, como recomendación, la utilización de la opción <span style="font-family: Courier New, Courier, monospace;">--add-transaction</span> que nos permitirá probarlo con comodidad y corregir los errores.<br />
<br />
Una herramienta imprescindible si usas PostgreSQL.<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://apgdiff.startnet.biz/" target="_blank">Another PostgreSQL Diff Tool (apgdiff)</a></li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com1tag:blogger.com,1999:blog-1763183641342103044.post-65786958011987472822012-07-01T19:48:00.001+02:002012-07-02T09:20:46.785+02:00JBoss Open Forum 2012, 6-06-12, Madrid<div style="text-align: right;">
<div style="text-align: left;">
</div>
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCpYQEkqx1-sf7HBXpAvIO7pmRhgsN9RDkb62RZsMxty-6qT5njGl-CsPMWC6v6fKouMgoJoOcFi9OvC4gRCXWoVS2P96QAUfXOAO-VF3MS4Fu2dFyptEjWpdiFxeDKfnU13aFdgLqH5c/s1600/img-banner-general-es.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiCpYQEkqx1-sf7HBXpAvIO7pmRhgsN9RDkb62RZsMxty-6qT5njGl-CsPMWC6v6fKouMgoJoOcFi9OvC4gRCXWoVS2P96QAUfXOAO-VF3MS4Fu2dFyptEjWpdiFxeDKfnU13aFdgLqH5c/s1600/img-banner-general-es.jpg" /></a></div>
<br />
El pasado 6 de Junio asistí al JBoss Open Forum 2012 en el que Red Hat presentaba muchos avances en sus soluciones de middleware empresariales (JBoss EAP 6, JBoss EDS, etc) así como casos de éxito en implementaciones de soluciones presentadas por las propias empresas cliente.<br />
<br />
<span style="background-color: white;">La verdad es que, de los últimos eventos de este tipo a los que he asistido, ha sido el que más me ha satisfecho. Tengo que destacar la excelente organización, sesiones con contenidos de enorme interés y ponentes a la altura de dichas ponencias.</span><br />
<br />
JBoss fue durante un tiempo nuestro (me refiero en mi trabajo) Servidor de Aplicaciones <i>"por defecto"</i>. Las versiones 3.x de JBoss funcionaban bien. Era rápido y tenía un motor de JMS francamente bueno. Aún a pesar de sus conocidos inconvenientes en cuanto a la gestión de configuración y el complicado ajuste de los <i>class loaders</i>, el servidor era de lo mejorcito no sólo entre los servidores Open Source, sino en general.<br />
<br />
Sin embargo, a partir del año 2006, en el que se lanzó la especificación JEE 5, no veíamos avances consistentes en el Servidor de Aplicaciones en cuanto a dicha especificación. La compra ese mismo año, de JBoss por parte de Red Hat tampoco ayudó a agilizar el despegue de versiones y el lanzamiento de una nueva versión certificada JEE 5.... La verdad es que JBoss 4 nos decepcionó y, volvimos a realizar un examen a otros servidores. <span style="background-color: white;">2006 fue el año en el que coincidió una especie de pausa en JBoss (supongo que debida a la reestructuración e integración en Red Hat tras su compra), con el lanzamiento de Glassfish, el primer Servidor de Aplicaciones que soportaba JEE 5 y que era, además, la RI (Implementación de Referencia). Con lo que nos "pasamos" a Glassfish.</span><br />
<span style="background-color: white;"><br /></span><br />
... Y hasta ahora. Llevamos trabajando con Glassfish como "nuestro" servidor de aplicaciones <i>"por defecto"</i> desde 2006. Pero las cosas pueden cambiar. Glassfish tenía novedades de las que JBoss adolecía: consola web, una configuración única... sin embargo, su motor JMS era menos configurable que el de JBoss, y tampoco tenía (y sigue sin tener) un browser JNDI. Por tanto, que JBoss llegara a tener las cosas que carecía e igualar o superar a Glassfish era una cuestión de tiempo que, al parecer, ha concluido.<br />
<br />
En el JBoss Open Forum 2012 comprobé que JBoss había recuperado su ritmo, su innovación y su buen hacer y me enseñaron cosas que, la verdad, me impresionaron mucho y gratamente:<br />
<ul>
<li>El nuevo servidor de aplicaciones se había reescrito por completo, según Pilar Bravo (JBoss Solution Architect, Red Hat). Y nos presentaban un renovado servidor JEE 6 certificado con mejoras aparentes a las que tenemos en Glassfish:</li>
<ul>
<li>Configuración única</li>
<li>Varias consolas: además de la consola web, hay otras como REST o consola muy interesantes</li>
<li>Nuevo servidor JMS</li>
<li>Classloader más sencillo de configurar</li>
<li>... y otras maravillas de clustering que habrá que probar detenidamente.</li>
</ul>
<li>En cuanto a middleware, lo que más me llamó la atención fue:</li>
<ul>
<li>Nuevas versiones</li>
<ul>
<li>de su magnífico JBoss Rules</li>
<li>de JBPM</li>
</ul>
<li>Productos (¿nuevos?) que desconocía:</li>
<ul>
<li>JBoss EDS</li>
<li>JBoss ON</li>
</ul>
</ul>
</ul>
<div>
<br /></div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9I3xY-9ayzWqnJ6rd_O393TmEnXdLks0nUVZXBb-M0Zwh3slTUD-mUihftPp0RU4izOgRKZ6NG-a4bLpZWE2ys0HGOgodO6W_juFpZljIUdjz8h5FzCsxlyqirSO34Nul6c3gzBIIcME/s1600/21062012533.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9I3xY-9ayzWqnJ6rd_O393TmEnXdLks0nUVZXBb-M0Zwh3slTUD-mUihftPp0RU4izOgRKZ6NG-a4bLpZWE2ys0HGOgodO6W_juFpZljIUdjz8h5FzCsxlyqirSO34Nul6c3gzBIIcME/s320/21062012533.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Imagen (tomada con mi móvil ;-) de una sesión</td></tr>
</tbody></table>
<div>
<b><a href="http://es.redhat.com/products/jbossenterprisemiddleware/operations-network/">JBoss ON</a> (Operations Network)</b> es una aplicación de monitorización de servicios. Una especie de Nagios+Caqti, para entendernos, pero especializado en servicios JBoss. Además, se puede combinar con Nagios para un control mucho más pormenorizado de los aspectos de cada servicio.</div>
<div>
<br /></div>
<div>
<b><a href="http://es.redhat.com/products/jbossenterprisemiddleware/data-services/">JBoss EDS</a> (Enterprise Data Services Platform)</b> es una plataforma de virtualización de datos que permite integrar datos de diversas fuentes y exponerlos en bases de datos virtuales accesibles a través de interfaces estándar como JDBC. </div>
<div>
<br /></div>
<div>
La presentación de este producto corrió a cargo de Karoly Nagy (Senior Solution Architect, Red Hat). Debo decir que fue una presentación excelente: concisa, al grano y con ejemplo/demo rotundo. Este producto realmente me ha impresionado mucho, mucho. ¡Ya me hubiera gustado tener a mano este producto hace algunos años...! Considero que un caso de uso típico (y a mi profesionalmente se me han dado unos cuantos) es el clásico caso de migración de subsistema (backoffice, frontoffice...) o de tecnología en el que te encuentras con que existen múltiples fuentes de datos cuya migración simultánea se hace compleja de implementar y, sobre todo, de poner en producción. JBoss EDS me parece un fantástico "pegamento" y entre los sistemas nuevos y los antiguos, sirviendo de carretera provisional mientras se realizan migraciones parciales de una gran implantación escalonada que puede durar muchos meses o años.</div>
<br />
Las ponencias sobre casos de éxito fueron, la mayoría, muy interesantes. Salvador Santander, del Departamento de Desarrollo de Tecnologías de Información de la Empresa Pública del Suelo de Andalucía (EPSA) puso la nota simpática y desenfadada a una buena exposición, muy cercana y realista, sobre su experiencia con Red Hat. De ésta y otras exposiciones de "Casos de éxito" me quedo con dos conclusiones:<br />
<ol>
<li>La satisfacción con el nivel de servicio de soporte por parte de Red Hat es buena. Tanto, que continuarán con ellos para proyectos de clustering y misión crítica</li>
<li>Da la sensación de que ya (por fin) hay en España consultores y servicio de soporte suficiente y de calidad.</li>
</ol>
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://opensource.com/sites/default/files/imagecache/image-full-size/images/ecards/OSDC_mothersday_520_9251077_0512LL.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://opensource.com/sites/default/files/imagecache/image-full-size/images/ecards/OSDC_mothersday_520_9251077_0512LL.png" /></a></div>
<br />
En resumen, me quedé con una buena impresión en general tanto de los nuevos productos de JBoss en el aspecto técnico, como de la aparente consolidación de Red Hat en España como compañero de viaje a la hora de afrontar nuevos proyectos y retos.<br />
<br />
Este es un caso claro de éxito de los nuevos modelos de negocio del siglo XXI, basados en código abierto, apoyados en la comunidad y generando puestos de trabajo de calidad en empresas rentables.<br />
<br />
Enhorabunena, Red Hat.<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.redhatjboss.es/recursos/">Recursos del evento</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-84048535797404922152012-06-12T19:21:00.000+02:002012-12-11T00:24:26.480+01:00Migrando a JEE 6 / EJB 3.1 (I)<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_LI5LA48LcCrq6RgWOQSYnvxSJL2qSblHzdkESIVz7UJ1420Kqs1JRkgA0JG-Yp7MDWioErrL9tMum9zN346kwQa9j1nX6rJw9RRDJ6DEd3JyXXwacKwJqS4LetP2I3eXqSp-UBtB8iQ/s1600/coffee_t.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_LI5LA48LcCrq6RgWOQSYnvxSJL2qSblHzdkESIVz7UJ1420Kqs1JRkgA0JG-Yp7MDWioErrL9tMum9zN346kwQa9j1nX6rJw9RRDJ6DEd3JyXXwacKwJqS4LetP2I3eXqSp-UBtB8iQ/s200/coffee_t.png" width="200" /></a></div>
<span style="font-family: tahoma;">
</span>
<blockquote>
<span style="font-family: tahoma;"><i>“I’ve finally learned what ‘upward compatible’ means. It means we get to keep all our old mistakes.”
</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Dennie van Tassel</span></div>
<br />
La especificación JEE 6 junto con la enorme lista de nuevas tecnologías que comporta (EJB 3.1, JAX-RS 1.1, JAX-WS 2.2, Java Servlet 3.0, etc...) está disponible desde diciembre de 2009. A pesar de haber pasado 2 años y medio, la verdad es que apenas he podido ponerla en funcionamiento en apenas un par de nuevos proyectos.<br />
<ul>
</ul>
De esta nueva especificación destaca especialmente la especificación EJB 3.1 con <a href="http://www.dosideas.com/noticias/java/528-ejb-31-un-paso-importante-hacia-la-madurez.html">muchas, potentes y útiles novedades</a>. Sin embargo, en la adopción de esta especificación me he encontrado con algunos aspectos ásperos, incompatibilidades y diversos problemas indocumentados. Este artículo (y alguno que le sucederá) intentará ahorrar al lector interesado, al menos, el tiempo que yo he perdido intentando hacer funcionar cosas que <i>teóricamente</i> (en base a la documentación) <i>deberían</i> funcionar.<br />
<br />
<h2>
1. Incompatibilidad de la notación <span style="font-family: 'Courier New', Courier, monospace;">@Webservice</span> con la vista sin interfaz (no-interface view)</h2>
<div>
Supongamos que tienes un EJB 3.0 publicado como Webservice, así:</div>
<br />
<pre class="brush:java; gutter: false;">
/**
* Stateless Session EJB 3.0
* @author szarza
*/
@Stateless(name="CacheService")
@TransactionManagement(TransactionManagementType.BEAN)
@WebService(serviceName="CacheService",name="CacheService")
public class CacheServiceBean implements CacheServiceLocal {
</pre>
<br />
Si vas a migrar a EJB 3.1, puedes tener la tentación de eliminar la interfaz local y usar la vista sin interfaz para simplificar tu proyecto... pero, lamentablemente, al eliminar la interfaz local, en Glassfish 3.1 me encuentro con un desagradable mensaje en despliegue:<br />
<br />
<pre class="brush:plain; gutter: false;">[#|2012-06-11T15:43:38.754+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.core.com.sun.enterprise.v3.server|_ThreadID=108;_ThreadName=Thread-2;|Cannot resolve reference Local ejb-ref name=cestel.services.cache.timer.CacheUpdaterTimedBean/cacheService,Local 3.x interface =cestel.services.cache.facade.CacheServiceLocal,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session
java.lang.RuntimeException: Cannot resolve reference Local ejb-ref name=cestel.services.cache.timer.CacheUpdaterTimedBean/cacheService,Local 3.x interface =cestel.services.cache.facade.CacheServiceLocal,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session...
</pre>
<br />
En definitiva: simplemente no funciona. La notación @Webservice es incompatible con la vista sin interfaz. Puede parecer más o menos lógico... pero no lo he visto en la documentación por ninguna parte.<br />
<br />
<h2>
2. Incompatibilidad de la notación <span style="font-family: 'Courier New', Courier, monospace;">@Path</span> y <span style="font-family: 'Courier New', Courier, monospace;">@Produces</span> en un módulo ejb</h2>
<div>
De la misma forma que se puede "publicar" de manera sencilla un EJB como un SOAP webservice JAX-WS simplemente añadiendo la notación <span style="font-family: 'Courier New', Courier, monospace;">@Webservice</span>, podría ser igualmente sencillo publicarlo como un webservice RESTful (JAX-RS) añadiendo la notación <span style="font-family: 'Courier New', Courier, monospace;">@Path</span> y <span style="font-family: 'Courier New', Courier, monospace;">@Produces</span>... pero no. Al menos en Glassfish 3.1.2 no es posible publicar un webservice REST en un módulo EJB. Esto me ha parecido un verdadero engorro, ya que nos obliga a realizar un módulo war sólo para esto.</div>
<div>
<br /></div>
<div>
En definitiva, si necesitáis un servicio REST, debes hacer un módulo war.<br />
<br />
El próximo capítulo lo dedicaré a la adaptación a la nueva definición de JNDI portable y sus sorpresas inexplicables (por poco documentadas).</div>
<div>
<br /></div>
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.dosideas.com/noticias/java/528-ejb-31-un-paso-importante-hacia-la-madurez.html">EJB 3.1: un paso importante hacia la madurez</a></li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-20137139539014256402012-05-04T22:38:00.001+02:002012-05-05T12:35:03.521+02:00Analizar y procesar los argumentos de línea de comandos en Java<h2 style="text-align: right;">
(Parsing and processing command line arguments in Java)</h2>
<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnsAewBafvIDjutX5KRXKr1K47BsVtGOxa8PfSbaiALqtmh5GjMj2kPtUoG8tm13xLmwyrqnXTTaftMjSYtvdFjEQWbebDirWhlOl8bChqviES6yByUKEFo7z2HZF4TO0V18Pef-iK6mM/s1600/victorinox.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnsAewBafvIDjutX5KRXKr1K47BsVtGOxa8PfSbaiALqtmh5GjMj2kPtUoG8tm13xLmwyrqnXTTaftMjSYtvdFjEQWbebDirWhlOl8bChqviES6yByUKEFo7z2HZF4TO0V18Pef-iK6mM/s200/victorinox.jpg" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>“19 Jan 2038 at 3:14:07 AM”</i></span></blockquote>
</div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">(End of the word according to Unix–2^32 seconds after January 1, 1970)</span></div>
<br />
Los límites tecnológicos son muy provisionales. Las cosas que aparentemente durarán mucho al final son más efímeras de lo que parece. El año pasado se agotaron oficialmente las direcciones IPv4 y me preguntaba, a propósito de la "<i>cita</i>" de hoy si, en el año 2038, aún existirán procesadores de 32 bits. El tema de este articulo, sin embargo, es una paradoja al inexorable paso del tiempo: seguimos necesitando realizar aplicaciones de consola que puedan invocarse a través de la línea de comandos.<br />
<br />
En java, podemos procesar una línea de comandos sencilla a partir del argumento del método <i style="font-family: "Courier New",Courier,monospace;">main</i>. Pero, si necesitamos procesar una línea de comandos más compleja, podemos enfrentarnos a un arduo trabajo. Nuestra aplicación puede necesitar características de procesado más complejas como:<br />
<ul>
<li>Argumentos con opciones</li>
<li>Análisis sintáctico (tipos de dato, restricciones, etc)</li>
<li>Valores por defecto en caso de omisión</li>
<li>Control de opciones obligatorias o requeridas</li>
<li>Generación de opción de ayuda</li>
<li>etc...</li>
</ul>
<br />
Por ejemplo, supongamos las siguientes opciones:<br />
<br />
<pre class="brush:plain;">Option (* = required) Description
--------------------- -----------
-?, -h show help
-c <integer: count=""> (default: 1)
--classpath, --cp <file: path1:="" path2:...="">
* -d <mm dd="" yy=""> some date
--output-file [File: file]
-q [Double: quantity]
-v, --chatty, --talkative be more verbose
</pre>
<br />
Procesar las opciones mostradas anteriormente por nuestra cuenta sería <i>reinventar la rueda</i>. Para ayudarnos en esta tarea existen múltiples librerías que nos permiten realizar un procesado de opciones de argumentos muy complejo en unas pocas líneas de código, de las que expondré una recopilación al final. En este artículo comentaré la que he utilizado: <i>JOpt Simple</i>.<br />
<br />
<br />
<img alt="JOpt Simple" height="37" src="http://pholser.github.com/jopt-simple/images/jopt-simple-logo.png" width="200" /><br />
Es la librería usada en OpenJDK. JOpt Simple permite realizar análisis de argumentos compatibles con la sintaxis POSIX <a href="http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap12.html"><tt>getopt()</tt></a> y <a class="externalLink" href="http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Options.html"><tt>getopt_long()</tt></a>, manteniendo toda la simplicidad posible. Como otras librerías, tiene opciones muy útiles:<br />
<ul>
<li>generación automática del texto (formateado) de la opción de ayuda</li>
<li>control de parámetros obligatorios en argumentos</li>
<li>control de tipos de parámetros </li>
<li>control de opciones de argumentos</li>
<li>valores por defecto</li>
<li>etc... </li>
</ul>
<br />
A continuación, un ejemplo de uso:<br />
<br />
<pre class="brush:java;"> private static final String IMPORTED = "imported";
private static final String A_H = "h";
private static final String A_P = "p";
private static final String A_U = "u";
private static final String A_URL = "url";
private static final String A_E = "e";
private static final String A_I = "i";
private static final String A_Q = "q";
private static final String A_V = "v";
private static final String A_GC = "gc";
private static final String A_DR = "dry-run";
public static void main(String[] args) {
OptionParser parser = new OptionParser() {
{
acceptsAll( asList( "h", "?", "help" ), "Muestra la ayuda" );
acceptsAll( asList( A_V, "verbose" ), "Muestra información detallada" );
accepts( A_URL, "Url de conexión al repositorio" ).withRequiredArg().ofType( String.class ).defaultsTo( "//localhost:1099/jackrabbit.repository" );
acceptsAll( asList( A_U, "user"), "Usuario" ).withOptionalArg().ofType( String.class ).defaultsTo( "gesif" );
acceptsAll( asList( A_P, "password"), "Contraseña" ).withRequiredArg().ofType( String.class ).defaultsTo( "gesif" );
acceptsAll( asList( A_E, "export"), "Exportación de consulta a directorio (requiere -q)" ).withRequiredArg().ofType( String.class ).defaultsTo( "." ).describedAs( "directorio" );
acceptsAll( asList( A_I, "import"), "Importación de ficheros del directorio" ).withRequiredArg().ofType( String.class ).describedAs( "Path completo de ficheros a importar (se permiten comodines)" );
acceptsAll( asList( A_Q, "query"), "Consulta a realizar" ).withRequiredArg().ofType( String.class ).describedAs("consulta XPATH");
accepts( A_GC , "Ejecuta la limpieza de borrado (requiere -u y -p)" ).withRequiredArg().ofType( String.class ).describedAs("repository home");
accepts( A_DR , "Ejecución de importación de prueba (no importa)");
}
};
OptionSet options = parser.parse( args );
Date time = new Date();
try {
if ( args.length < 1 || options.has( A_H ) ) {
parser.printHelpOn( System.out );
System.out.println("Ejemplos:\n" +
" RTool -q \"//*[@gst:file and @g:stepId = 13872238]\" -e /home/szarza/tmp3\n" +
" RTool -q \"//*[@gst:file and @g:stepId=20754674]\" -e . --url //192.168.20.12:1099/jackrabbit.repository\n" +
" RTool --url //192.168.20.12:1099/jackrabbit.repository --import ./fc15099e-d586-4046-afd1-8fc9c03bdf17.0002.pdf");
System.exit(0);
}
....
</pre>
<br />
Como se ve en este ejemplo, con Jopt Simple se puede realizar todo el control de opciones y argumentos de una forma rápida y sencilla. Sin embargo no es la única, hay realmente muchas:<br />
<ul>
<li><a href="http://jewelcli.lexicalscope.com/">JewelCli</a></li>
<li><a class="externalLink" href="http://jcommander.org/">JCcommander</a> </li>
<li><a class="externalLink" href="http://jakarta.apache.org/commons/cli/">Jakarta Commons Cli</a></li>
<li><a class="externalLink" href="http://www.javaworld.com/javaworld/jw-08-2004/jw-0816-command.html"> Dr. Matthias Laux</a></li>
<li><a class="externalLink" href="http://te-code.sourceforge.net/"> TE-Code Command</a></li>
<li><a class="externalLink" href="http://jargp.sourceforge.net/"> jargp</a></li>
<li><a class="externalLink" href="http://jcmdline.sourceforge.net/"> jcmdline</a></li>
<li><a class="externalLink" href="http://www.urbanophile.com/arenn/hacking/download.html"> java-getopt</a></li>
<li><a class="externalLink" href="http://dolphin.sourceforge.net/getopt/"> dolphin getopt</a></li>
<li><a class="externalLink" href="http://jargs.sourceforge.net/"> jargs</a></li>
<li><a class="externalLink" href="http://jcommando.sourceforge.net/"> jcommando</a></li>
<li><a class="externalLink" href="http://www.martiansoftware.com/jsap/"> jsap</a></li>
<li><a class="externalLink" href="https://args4j.dev.java.net/"> args4j</a></li>
<li><a class="externalLink" href="http://www.dpml.net/util/cli/index.html"> DPML CLI (Jakarta Commons CLI2 fork</a></li>
<li><a class="externalLink" href="http://www.objectmentor.com/resources/articles/Clean_Code_Args.pdf"> Object Mentor CLI article (more about refactoring and TDD)</a></li>
<li><a class="externalLink" href="http://code.google.com/p/parse-cmd/"> parse-cmd</a></li>
<li><a class="externalLink" href="http://code.google.com/p/cli-parser/"> cli-parser</a></li>
<li><a class="externalLink" href="http://www.cs.ubc.ca/spider/lloyd/java/argparser.html"> argparser</a></li>
<li><a class="externalLink" href="http://clajr.sourceforge.net/"> clajr</a></li>
<li><a class="externalLink" href="http://ostermiller.org/utils/CmdLn.html"> CmdLn</a></li>
<li><a class="externalLink" href="http://naturalcli.sourceforge.net/"> naturalcli</a></li>
<li><a class="externalLink" href="http://www.snaq.net/java/JCLAP/"> JCLAP</a></li>
<li><a class="externalLink" href="http://ritopt.sourceforge.net/"> ritopt</a></li>
<li><a class="externalLink" href="https://github.com/alexy/optional"> optional (scala, multiple github forks)</a></li>
</ul>
Usé JOpt Simple por ser una librería muy versátil y muy sencilla de usar. Sin embargo, tengo que reconocer que, en mi búsqueda de librerías, <a href="http://jewelcli.lexicalscope.com/">JewelCli</a> y <a href="http://jcommander.org/">JCommander</a> me dejaron impresionado por su elegancia y limpieza. JOpt Simple es una librería al estilo clásico, donde la definición de sintaxis es programática. JewelCli y JCommander son librerías con un nuevo enfoque actualizado, que usan un estilo declarativo para la definición de sintaxis, usando anotaciones. Estas últimas librerías me parecieron más adecuadas para un proyecto mayor, con más opciones y/o que fuese a tener un mantenimiento mayor.<br />
<br />
En todo caso, creo que en una próxima ocasión probaré JewelCli. Y tu, ¿has probado alguna? ¿qué opinión tienes?<br />
<br />
<b>P.D.: Por cierto, feliz <a href="http://en.wikipedia.org/wiki/Star_Wars_Day">Stars Wars Day</a> a todos!! ... y <a href="https://plus.google.com/u/0/100086431194214967216/posts/ec73fKZJvBy%20">#maythe4thbewithyou.</a> </b><br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://pholser.github.com/jopt-simple/">JOpt Simple</a></li>
<li><a href="http://jewelcli.lexicalscope.com/">JewelCli</a></li>
<li><a href="http://jcommander.org/">JCommander</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-16641847880571862022012-04-15T10:37:00.000+02:002012-05-18T18:08:33.749+02:00Transacciones autónomas en PostgreSQL<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdgVHZw2jk7HZemor_7YKNd-r3hQLLr7cKTeCMWQtrSW77BvWF22DaMMQCZ7xm6OwgwOrHYDrIGnGu9BXW2ztJwRmGPiF_BTJbE7XPQc3x03AtLVgyGrAFA_O_5s3w-4TF2VIbeK0AV1w/s320/file000515487979.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdgVHZw2jk7HZemor_7YKNd-r3hQLLr7cKTeCMWQtrSW77BvWF22DaMMQCZ7xm6OwgwOrHYDrIGnGu9BXW2ztJwRmGPiF_BTJbE7XPQc3x03AtLVgyGrAFA_O_5s3w-4TF2VIbeK0AV1w/s200/file000515487979.jpg" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>The cheapest, fastest, and most reliable components are those that aren’t there.</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Gordon Bell.</span></div>
<br />
En algunos casos, necesitamos que ciertas operaciones de una transacción de base de datos sean realizadas aunque la transacción se deshaga con un <i>rollback</i>. Por ejemplo, imaginemos que tenemos una función o procedimiento almacenado en la que hemos agrupado 10 operaciones. Cuando dicha función se llame, se ejecutará en un contexto transaccional, es decir, se realizará una transacción con dichas 10 operaciones de forma atómica (o todas, o ninguna). Supongamos que queremos garantizar que un subconjunto de esas operaciones (por ejemplo un par de ellas que hacen auditoría de la propia llamada) se realicen siempre, con independencia de las demás: en este caso necesitamos una transacción autónoma.<br />
<br />
Las transacciones autónomas (<i>Autonomous Transactions</i>) permiten suspender el contexto de la transacción en curso (llamante), realizar una transacción independiente y reanudar el contexto de la transacción llamante sin afectar su estado. Los casos de uso típicos de uso son funcionalidades cuyos cambios queremos que persistan con independencia de la transacción que las llama: trazado (logging), operaciones de auditoría, contadores, funciones de propósito general...etc.<br />
<br />
Un caso que se me ha dado recientemente es el de realizar una transacción batch muy muy larga (de importación de gran cantidad de datos), donde la unidad de importación supone operaciones de modificación (inserción o actualización) en varias tablas. Imaginemos que importamos usuarios con todos sus datos: dirección, provincia, datos bancarios, teléfonos, etc... Cada usuario puede suponer 8 o 10 operaciones en diversas tablas. Si tenemos que importar 30.000 usuarios, podemos encontrarnos con una transacción compuesta por 300.000 operaciones de inserción/actualización. Este tipo de transacciones tan grandes exige muchos recursos de un servidor de base de datos: crea ocupación de memoria y genera muchos puntos de bloqueos que podrían socavar el desempeño de un sistema en producción. Una forma de solucionar un problema así es realizar una confirmación de datos por cada unidad de importación. Es decir, que el bucle general de importación (que ya se ejecuta en un contexto transaccional) llame a una función que realiza y confirma la tarea de importación de una unidad (un usuario en el ejemplo) en una transacción autónoma, con lo cual cada usuario se procesaría de forma atómica, sin que la transacción general acumule trabajo.<br />
<br />
Con Oracle, las transacciones autónomas se declaran sin mayor dificultad usando la directiva:<br />
<br />
<pre class="brush:sql; gutter: false;">PRAGMA AUTONOMOUS_TRANSACTION;</pre>
<br />
Sin embargo, <b>en PostgreSQL <a href="http://www.postgresql.org/docs/9.1/static/plpgsql-porting.html#CO.PLPGSQL-PORTING-PRAGMA">las transacciones autonomas no están soportadas</a></b>. No hay forma de hacerlo de forma declarativa. Sólo hay una forma de hacerlo (con dos enfoques, como veremos enseguida): realizando la parte que queremos que sea <i>autónoma</i> en otro contexto transaccional, es decir, en otra conexión a la base de datos:<br />
<ol>
<li>Usando un lenguaje de programación externo (<i>untrusted</i>). Es decir, reducir la función PL/PgSQL a la parte que queremos garantizar su ejecución (la parte que queremos que sea <i>autónoma</i>) y realizar el resto en un lenguaje de programación externo a la base de datos. La función se llamará en una nueva conexión</li>
<li>Usando dblink. Esta opción, es parecida a la anterior, pero usando siempre PL/PgSQL. Es decir, realizamos la transacción autónoma en una nueva conexión usando dblink.</li>
</ol>
<br />
<br />
<h2>
dblink</h2>
dblink es un módulo del <i>contrib</i> de PostgreSQL que permite realizar conexiones y realizar consultas a bases de datos locales o remotas dentro de una sesión. Con un ejemplo se verá más claro:<br />
<br />
<pre class="brush:sql; gutter: false;">SELECT nombre, apellidos
FROM usuario INNER JOIN
dblink('dbname=otrabasededatos port=5432 host=localhost_u_otro' ||
'user=usuario password=password',
'SELECT direccion, poblacion, provincia from usuario')
AS u(direccion varchar, poblacion varchar, provincia varchar)
ON usuario.id = u.id;
</pre>
<br />
En el anterior ejemplo, realizamos un JOIN entre dos tablas de dos bases de datos distintas (en el mismo host u otro, eso da igual). Es decir, en la sesión en curso, y a través de las funciones de dblink, se crea una conexión sobre la que enviamos nuestra query. Si esto lo hacemos contra el mismo servidor y misma base de datos... <i>voilá</i>: ya tenemos una conexión nueva y, por tanto, un contexto transaccional diferente en el que podemos ejecutar nuestra transacción de forma independiente (es otra conexión).<br />
<br />
Veamos un ejemplo de cómo usarlo. Supongamos el ejemplo del inicio, donde tenemos un cursor que recorremos en el que, para cada registro, debemos realizar un par de operaciones transaccionales de forma independiente (autónoma). Aprovecharemos el ejemplo también para ilustrar cómo se puede realizar una inserción y obtener la clave del elemento recién insertado para la siguiente sentencia.<br />
<br />
<pre class="brush:sql; gutter: true;">for usuario in (select * from iusuarios) loop
raise notice 'Procesando usuario->, %',usuario.id || '-' || usuario.nombre;
PERFORM dblink_connect_u('dbname=dbname connect_timeout=5');
PERFORM dblink_exec('begin;');
l_dbl_sql :=
'insert into u2 (name,edad) values (' ||
quote_nullable(l_name) || ', ' ||
coalesce(l_edad::varchar,'null') || ', ' ||
'0) returning id;';
raise notice '[ALTA] SQL INSERT u2: %', l_dbl_sql;
select id into l_user_id from dblink(l_dbl_sql) as d(id int4);
l_dbl_sql :=
'update otra_tabla set date = now() where id_user = ' || l_user_id || ';';
raise notice '[ALTA] SQL UPDATE otra_tabla: %', l_dbl_sql;
PERFORM dblink_exec(l_dbl_sql);
PERFORM dblink_exec('commit;');
PERFORM dblink_disconnect();
end loop;</pre>
<br />
Examinaremos el ejemplo, porque hay cosas interesantes que quiero destacar:
<br />
<ol>
<li>Linea 4: es importante especificar el timeout, para evitar <a href="http://balteus.blogspot.com.es/2011/01/statementtimeout-querytimeout-con.html">efectos indeseables</a>. Dado que se trata de la misma base de datos en el mismo servidor, no hay que especificar nada más.</li>
<li>Linea 5: inicio de la transacción, ya que hay más de una sentencia</li>
<li>Líneas 9 y 10: uso de las funciones <span style="font-family: "Courier New",Courier,monospace;">quote_nullable()</span> y <span style="font-family: "Courier New",Courier,monospace;">coalesce()</span> para garantizar el correcto escape de valores y la generación de 'null' cuando existan valores nulos. </li>
<li>Línea 14: ejemplo de ejecución de sentencia <span style="font-family: "Courier New",Courier,monospace;">INSERT</span> con dblink para obtención del registro recién insertado.</li>
<li>Línea 19: ejemplo de ejecución de sentencia <span style="font-family: "Courier New",Courier,monospace;">UPDATE</span> (o cualquier otra sentencia que no devuelva resultados)</li>
<li>Línea 21: confirmación de la transacción</li>
<li>Línea 22: desconexión</li>
<li>Líneas 11 y 17: es <b>muy importante</b> asegurarse de que terminamos las sentencias que enviamos a dblink con el separador de terminación <b>punto y coma (;)</b>. Un olvido puede hacer que nuestra función se detenga esperando la terminación.</li>
</ol>
Finalmente, recomiendo usar las funciones quote_nullable() para las fechas y cadenas y coalesce() para los valores numéricos para garantizar una correcta sintaxis y escapado de las sentencias. Si estás usando PostgreSQL 9.1 o superior puedes evitar ese engorro y usar la enormemente más cómoda función <a href="http://www.postgresql.org/docs/9.1/interactive/functions-string.html">format()</a>.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.dosideas.com/wiki/Transacciones_Autonomas_En_Oracle">Transacciones autónomas en Oracle (de DosIdeas)</a></li>
<li><a href="http://www.postgresonline.com/journal/archives/44-Using-DbLink-to-access-other-PostgreSQL-Databases-and-Servers.html">Using DbLink to access other PostgreSQL Databases and Servers</a></li>
<li><a href="http://www.postgresql.org/docs/9.1/static/dblink.html">Documentación de PostgreSQL de dblink</a> </li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com2tag:blogger.com,1999:blog-1763183641342103044.post-15114180894602266632012-03-06T13:50:00.004+01:002012-03-06T13:50:54.293+01:00Balteus cumple su tercer año<div style="text-align: right;">
<div style="text-align: left;">
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTUK3xWBxYASMDJoPzQYEta74sRPG7YxJ8GPxO14eG-2lPgwWCs1z5ovEEpFO22rsoL2RbS-ku6LRhBicFYZlpHMoI-jPu6Q9ck1O34TueEtj-xCnD4POsrf_lp8osueWRIAveUBNRJdk/s1600/balteus3.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTUK3xWBxYASMDJoPzQYEta74sRPG7YxJ8GPxO14eG-2lPgwWCs1z5ovEEpFO22rsoL2RbS-ku6LRhBicFYZlpHMoI-jPu6Q9ck1O34TueEtj-xCnD4POsrf_lp8osueWRIAveUBNRJdk/s400/balteus3.jpg" width="328" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">(Ilustración: Fran Barquero)</td></tr>
</tbody></table>
</div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>"¿Se acuerda de la araña que había en su ventana? Era naranja, con las patas verdes. La vio tejer una telaraña todo el verano. Un día puso un huevo. Luego el huevo eclosionó..." - Rick Deckard<br /><br />"Y salieron de él cientos de arañas... que se la comieron." - Rachael</i></span></blockquote>
</div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">- Blade Runner.</span></div>
<br />
Siguiendo con la tradición de los post de aniversario de este blog, comienzo el apunte con otra cita del único y excepcional film "Blade Runner". Si no habéis visto la película, este (como cualquier otro) es un buen momento para hacerlo. Si la habéis visto, volved a verla. Siempre descubriréis nuevos ángulos y elementos interesantes. Es una obra tremenda y absolutamente extraordinaria.<br />
<br />
Este 6 de Marzo este blog cumple tres años. El hecho de mantener un blog durante tres años supone claramente que no es una ocurrencia momentánea, sino hay por mi parte un compromiso claro con él y que este proyecto mío del blog es algo consolidado. No obstante, un blog sin sus correspondientes actualizaciones no es nada, así que haré un esfuerzo por incrementar el número de artículos.<br />
<br />
El número tres es un número especial para este blog. No en vano el título del blog está dedicado a 3 estrellas (ver <a href="http://balteus.blogspot.com/p/acerca-de-balteus.html">Acerca de Balteus</a>). Ese motivo, esas mágicas tres estrellas, han servido de base para la ilustración especialmente realizada para la ocasión por el genial ilustrador Fran Barquero. Gracias Fran (esto se va a convertir en otra tradición...).<br />
<br />
Tengo un montón de temas y artículos en mente para este año que espero sean de tú interés. <br />
<br />
Un saludo a todos.Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com2tag:blogger.com,1999:blog-1763183641342103044.post-18761063624412205732012-02-28T15:11:00.000+01:002012-02-28T15:14:39.869+01:00Orden y formato al código PL/pgSQL<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWeSVyIjJ4cNPQEQ-q5y4VI_VqzOyWMh-ZPPyz7lXZVFsjxUhIPi5QLNJfOcMB0W3_9jOrAqbv6UZFhNIZGC_LhZMfNFP3YrmNMdfwWZtbxNr3Ic0AJXwlEKVaiC4KoUQyCuBJN0eq67U/s1600/file2471302811747.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWeSVyIjJ4cNPQEQ-q5y4VI_VqzOyWMh-ZPPyz7lXZVFsjxUhIPi5QLNJfOcMB0W3_9jOrAqbv6UZFhNIZGC_LhZMfNFP3YrmNMdfwWZtbxNr3Ic0AJXwlEKVaiC4KoUQyCuBJN0eq67U/s200/file2471302811747.jpg" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>“Any code of your own that you haven’t looked at for six or more months might as well have been written by someone else.”</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Eagleson’s Law</span></div>
<br />
Leer y entender un trozo de código de unas pocas líneas es fácil, aunque haya sido escrito como si se hubiese caído al suelo y esparcido por toda la habitación. Ahora bien, si tenemos que leer unos cuantos cientos o miles de líneas, la cosa cambia bastante. Es fundamental tener un código ordenado y bien identado para facilitar la legibilidad.<br />
<br />
Existen muchas herramientas que facilitan o realizan directamente esta tarea. Son las llamadas herramientas de embellecimiento o formato ("code beautifiers/formatters tools"). La mayoría de los IDE's y editores tienen herramientas para una gran variedad de lenguajes... salvo para PL, donde me he encontrado bastantes carencias.<br />
<br />
Si necésitáis una herramienta de este estilo, una de las mejores que me he encontrado es <b><a href="http://psti.equinoxbase.com/">Pl/Sql tidy</a></b>. Algunas de sus características son:<br />
<ul>
<li>Identación por bloques</li>
<li>Compactación</li>
<li>Ajuste de mayúsculas/minusculas</li>
<li>Alineamiento vertical en asignaciones</li>
</ul>
<div>
El uso de la herramienta es a través de línea de comando, pero también podéis usar la interesante <a href="http://psti.equinoxbase.com/cgi-bin/handler.pl">versión online disponible</a>.</div>
<div>
<br /></div>
<div>
Funciona con PL/pgSQL.</div>
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://psti.equinoxbase.com/">PL/SQL Tidy</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-90035152653739436832012-02-01T23:11:00.001+01:002012-02-02T21:53:43.469+01:00Apache Commons DbUtils: sencillo, rápido, ligero<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv3r6TxU7Nh_vy8NgZyIONLeO9aKdqFPhP_lR6Pra9rLwdZzjLUHD0urV417rYPlbeTy1rcBKiNGhbzUbaUEv8rNTtLWOzmgXYk0QxJK9OGe-0c9-uf8GAvNsKHygFYgxVUKiWn2aSFZo/s200/PIC1068506068.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgv3r6TxU7Nh_vy8NgZyIONLeO9aKdqFPhP_lR6Pra9rLwdZzjLUHD0urV417rYPlbeTy1rcBKiNGhbzUbaUEv8rNTtLWOzmgXYk0QxJK9OGe-0c9-uf8GAvNsKHygFYgxVUKiWn2aSFZo/s200/PIC1068506068.jpg" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>“Controlling complexity is the essence of computer programming”</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Brian Kernigan</span></div>
<br />
Hoy traigo aqui otra de las joyas de <a href="http://commons.apache.org/">Apache Commons</a>: <a href="http://commons.apache.org/dbutils/">DbUtils</a>. Ya comenté en el artículo anterior <a href="http://balteus.blogspot.com/2009/09/banco-de-experiencias-iv-librerias.html">"Librerías imprescindibles en Java"</a> que, en cualquier projecto, antes de pensar en hacer nuestras <i>utilities</i>, debemos pasar por la página de Commons para ver las <a href="http://commons.apache.org/components.html">librerías existentes</a> antes de ponernos a <i>reinventar la rueda</i>. Pues bien, Commons tiene otra pequeña joya que he descubierto y aplicado recientemente con éxito.<br />
<br />
Hay ocasiones en las que no usamos un framework de mapeo tipo ORM (JPA/EclipseLink, Hibernate, Mybatis -antiguo iBATIS-) por varias razones: modelo muy cambiante, proyecto muy pequeño, necesitamos un control más fino de las consultas, generación dinámica, etc... En estos casos, no nos queda más remedio que usar directamente JDBC. Sin embargo JDBC es un API muy engorroso que requiere mucho código de limpieza de recursos y mucha fontanería a través de sus capas. Más del 80% de nuestro código JDBC es la instanciación de objetos del API, establecimiento de parámetros, liberación y cierre. <br />
<br />
<br />
DbUtils es un pequeño conjunto de clases diseñadas para hacer mucho más fácil el trabajo que hacemos con JDBC centrándonos en lo que queremos: consultar, actualizar, insertar. Especialmente nos ayuda en:<br />
<ul>
<li>Se encarga automáticamente de la fontanería previa (conexión y preparación) y de la limpieza, evitando posibles errores de liberación de recursos.</li>
<li>Rellena las propiedades de JavaBean automáticamente a partir de ResultSets. No es necesario copiar manualmente valores en instancias de beans.</li>
</ul>
Por todo la anterior, el uso de DbUtils reduce drásticamente la cantidad de código que necesitamos con JDBC. Por hacer una comparativa, yo díría que DbUtils es a JDBC lo que JDOM a javax.xml.<br />
<br />
Usar <b>DbUtils</b> es muy sencillo. Hay dos clases/interfaces principales que constituyen el corazón de DbUtils: <a href="http://commons.apache.org/dbutils/apidocs/org/apache/commons/dbutils/QueryRunner.html" style="font-family: "Courier New",Courier,monospace;">QueryRunner</a> y <a href="http://commons.apache.org/dbutils/apidocs/org/apache/commons/dbutils/ResultSetHandler.html" style="font-family: "Courier New",Courier,monospace;">ResultSetHandler</a>. <span style="font-family: "Courier New",Courier,monospace;">QueryRunner</span> se encarga de realizar todo el trabajo: abre la conexión, ejecuta la consulta o actualización y devuelve el resultado. Para devolver el resultado de diferentes formas se usan las distintas implementaciones de la clase <span style="font-family: "Courier New",Courier,monospace;">ResultSetHandler</span>, que permite devolver el resultado en una lista de POJO's, lista de arrays, lista de Map, etc...<br />
<br />
A continuación pongo un ejemplo simple de una pequeña DAO de una aplicación que tuviese que acceder a una base de datos PostgreSQL y a un AS/400 simultáneamente. En el ejemplo se pueden observar características muy importantes de ahorro de código y, por tanto, de su consecuencia más valiosa, ahorro de tiempo:<br />
<ul>
<li>No hay declaraciones de Connection, Statement y ResultSet.</li>
<li>No hay liberación de recursos (DbUtil lo hace automáticamente)</li>
<li>No es necesaria la engorrosa recolección de campos a través de la iteración del ResultSet. Podemos devolver las consultas en un Map<String, Object> (NombreCampo, Valor) o en un JavaBean cuyas propiedades coincidan con los campos que devuelva nuestra consulta.</li>
</ul>
<br />
<br />
<pre class="brush:java; gutter: false;">/**
Suponemos una clase DAO cualquiera de acceso a datos
*/
public class ASDao {
private AS400JDBCDataSource asDataSource;
private PGSimpleDataSource pgDataSource;
private QueryRunner qr;
public ASDao() throws Exception {
// El datasource puede instanciarse...
asDataSource = new AS400JDBCDataSource("host4.cestel.es","asuser","xxxxxx");
// U obtenerse a partir de un JNDI de un contenedor
pgDataSource = new InitialContext().lookup("java:comp/env/jdbc/pgDS");
qr = new QueryRunner(asDataSource);
qrp = new QueryRunner(pgDataSource);
}
/**
Realiza una consulta parametrizada (que debe devolver una sóla fila) y
devuelve un Map<String,Object> con el nombre del campo
y su valor. Se asume que la consulta devuelve una sóla fila.
Son apenas dos líneas.
*/
public Map<String,Object> findData(String clientCode, String debtCode)
throws SQLException {
MapHandler result = new MapHandler();
return qrp.query(
"select c.id, c.code, de.id, de.customer_debt_id, dos.id, dos.code\n" +
"from debt de join dossier dos on de.dossier_id = dos.id \n" +
"join customer c on dos.customer_id = c.id\n" +
"where customer_debt_id = ?\n" +
"and c.code=?\n" +
"and end_process_date is null", result,debtCode, clientCode);
}
/**
Realiza una consulta parametrizada y devuelve el resultado como una lista de
JavaBeans "TablaAS". La creación de la lista y "llenado" de los objetos corre
por su cuenta. Lo único que tenemos que hacer es crear la clase TablaAS con
propiedades (getter, setter). Las propiedades de los POJO (JavaBeans) que
se "llenaran" serán aquellas cuyo nombre coincida con el campo devuelto.
Dos líneas (más la clase)
*/
public List<TablaAS> findByClient(String clientCode) throws SQLException {
ResultSetHandler<list<TablaAS>> blh = new BeanListHandler<TablaAS>(TablaAS.class);
return qr.query("select * from CESQ.TABLA_AS where CODCLTE = ?", blh,clientCode);
}
/**
Ejemplo de la misma consulta devuelto como un array
o como una lista de POJO's (JavaBean)
*/
public void test() throws SQLException {
ArrayHandler ah = new ArrayHandler();
ResultSetHandler<list<TablaAS>> h =
new BeanListHandler<TablaAS>(TablaAS.class);
Object[] resultArray =
qr.query("select * from CESQ.TABLA_AS FETCH FIRST 2 ROWS ONLY", ah);
List<TablaAS> result =
qr.query("select * from CESQ.TABLA_AS FETCH FIRST 2 ROWS ONLY", h);
}
}
</pre>
<br />
Como todas las cosas, obviamente DbUtils tiene un <i>target</i> concreto de aplicación, no es una bala de plata para todo. Ahora bien, si no devolvemos conjuntos de datos grandes, podría usarse como perfecto sustituto de JDBC con un mínimo impacto en el rendimiento y con una importante mejora en legibilidad y mantenibilidad.<br />
<br />
Puedes ver <a href="http://commons.apache.org/dbutils/examples.html">más ejemplos</a> en el sitio de DbUtils.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://commons.apache.org/dbutils/">Apache Commons DbUtils</a> </li>
<li><a href="http://commons.apache.org/">Apache Commons</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com3tag:blogger.com,1999:blog-1763183641342103044.post-7179583707037381192012-01-18T08:52:00.001+01:002012-02-02T19:51:39.020+01:00Expo NASA: La aventura del espacio<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC4WGJo0GNAGQAopmCBbi-q7UMQYw3XAVnOBm4VyqGzC3iqhuMNXul_rL_C4JWJNkaiYlEoP1SrSTD6paQLYe9eDykPAq0XaoyLpGqFZz0lU_HmwYbIk26j3z_OCS14QHXuWZBCyVO6v8/s320/cartel+baja.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC4WGJo0GNAGQAopmCBbi-q7UMQYw3XAVnOBm4VyqGzC3iqhuMNXul_rL_C4JWJNkaiYlEoP1SrSTD6paQLYe9eDykPAq0XaoyLpGqFZz0lU_HmwYbIk26j3z_OCS14QHXuWZBCyVO6v8/s320/cartel+baja.png" width="265" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>Todo lo que una persona puede imaginar, otras podrán hacerlo realidad.</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;"><a href="http://es.wikipedia.org/wiki/Julio_Verne">Julio Verne</a> (1828-1905).</span></div>
<br />
<br />
La exposición itinerante que la NASA ha traído a Europa está en Madrid desde el pasado Diciembre. Es una visita obligada para curiosos y amantes de la astronáutica y una ocasión excepcional para poder contemplar instrumentos, maquinaria y réplicas de la tecnología actual y la que llevó al hombre a la luna hace casi 43 años.<br />
<br />
Pensaba ir a verla de todos modos, pero he tenido la suerte poder de ahorrarme los 16€ de la entrada entrada por ser <a href="http://amazings.es/2011/12/23/ya-tenemos-ganadores-del-concurso-nasamazings-para-acudir-a-exponasa/">uno de los ganadores</a> del concurso promovido por <a href="http://amazings.es/">amazings.es</a> y la organización de la exposición, así que fui a verla el pasado domingo.<br />
<br />
Yuri Gagarin afirmó en una ocasión que su decisión hacia la astronáutica se la debía al excepcional Julio Verne. Y no es para menos. Él es uno de los personajes destacados en la primera sala que nos encontramos en la exposición, la de los <i>soñadores</i>, tras pasar una réplica de la pasarela de acceso a la parte superior del Saturno V y que daba acceso a la nave Apollo.<br />
<br />
No voy a detallar aquí el contenido de la exposición, que podéis encontrar en el propio dossier de prensa y en abundante información en la red, sino más bien mi impresión subjetiva y crítica de la misma.<br />
<br />
Lo más fascinante de la exposición es poder contemplar in situ y a tamaño real muchas de las cosas que me han fascinado y de las que he visto fotos cientos de veces. Constatas que, hasta que no lo ves con tus propios ojos, no te haces una idea del aspecto y tamaños reales de ciertos artefactos. Por ejemplo, el interior del módulo de ascenso del L.M (Módulo Lunar), tan pequeño, tan frágil... con un aspecto más parecido a un batiscafo que a una nave espacial. Una cosa es que sepas que pilotaban de pie y otra cosa es que lo compruebes con tus propios ojos. Llama la atención especialmente el minúsculo tamaño de ciertas cápsulas espaciales, especialmente la Mercury, que cabría en una furgoneta: meterse ahí dentro sobre un misil Redstone modificado era <i>realmente</i> como estar dentro de la cabeza de un misil balístico. A medida que recorría la exposición reflexionaba sobre el tremendo esfuerzo tecnológico que se realizó en tan pocos años, partiendo totalmente de cero.<br />
<br />
Cuando entras en la exposición, te ofrecen unas audioguías (<a href="http://es.wikipedia.org/wiki/IPod_touch">iPod touch</a>) que te presentan varias audiciones/videos por cada sala con información acerca de la misma en una cantidad claramente insuficiente y desproporcionada a las necesidades de información que requieren los objetos expuestos. Y aquí entramos en la parte más inacabada y decepcionante de la exposición: la información. Los objetos expuestos tienen unas etiquetas numéricas que puedes consultar en unos pequeños paneles (sobre los que nos agolpamos los visitantes), cuya brevísima y exigua descripción apenas te satisface y que, por si fuera poco, van apareciendo lentamente en presentación continua (no caben todos en las pantallas) en una desordenada mezcla entre inglés y español. Ya que ofrecen los iPods, la organización podría (por el mismo coste) haber añadido mucha más información multimedia de cada sala e incluso de cada artefacto, evitando así los corros que se forman sobre las pantallitas esperando que aparezca la descripción (que no información) del número que estamos buscando. En definitiva, el problema es que, salvo que sepas lo que estas viendo, me temo que la mayoría de la gente no puede "conocer" lo que está viendo, porque nadie se lo explica.<br />
<br />
Por otro lado, los iPod touch cuentan con una excelente pantalla de 3,5 pulgadas que ni siquiera se ha aprovechado para hacer más accesible la exposición a personas con discapacidad auditiva añadiendo subtítulos a los audios y vídeos que ofrece. Vamos, aquí parece que tras todo el esfuerzo, parece que la parte más importante, la de la información, la hubieran dejado a medias. No hacen falta más carteles, ni más grandes. Hubiera bastado con cargar suficiente material en los iPod's. Por otro lado, si en información están suspensos, tienen un cero absoluto en accesibilidad, y no por falta de medios, sino más bien por pura desidia, cosa que me parece totalmente imperdonable, tratándose de una exposición de este calibre.<br />
<br />
De hecho, la ausencia de información incluso en temas básicos es tan patente que la organización está constantemente respondiendo en twitter a la pregunta <i>"¿Hasta cuándo está la exposición?"</i>, ya que esa información no está disponible ni siquiera en la web oficial. Por cierto: es hasta el 15 de Junio.<br />
<br />
Para compensar esta falta de información, recomendaría leer algo sobre la carrera espacial y las misiones de la NASA, ver documentales al respecto, o ver la <a href="http://es.wikipedia.org/wiki/De_la_Tierra_a_la_Luna_%28miniserie%29">mini-serie "De la tierra a la luna"</a> antes de ver la exposición, si tenéis ocasión, para poder disfrutar la exposición al completo conociendo lo que se está viendo.<br />
<br />
Finalmente, me hubiera gustado llevarme algún recuerdo como alguna serie de maquetas de lanzaderas (titan, atlas, saturno, sts, etc...) oficial. De nuevo, absolutamente decepcionante: apenas algunos carísimos y atroces juguetes de goma, torcidos, que ni siquiera estaban a escala. No había forma de llevarse la famosa serie de lanzaderas o alguna maqueta más o menos decente de un Saturno V o de una lanzadera salvo pequeños pisapapeles metálicos monocolor con poco detalle.<br />
<br />
Una excelente exposición mal rematada y poco cuidada en los detalles. En todo caso, una exposición totalmente recomendable por única y excepcional.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.laaventuradelespacio.com/">La aventura del espacio</a></li>
<li><a href="http://www.laaventuradelespacio.com/sites/default/files/dossier%20prensa%20NASA.pdf">Dossier de prensa de la exposición</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com1tag:blogger.com,1999:blog-1763183641342103044.post-70088991733225398972011-12-18T02:27:00.000+01:002012-02-02T19:52:39.121+01:002011: 50 años en el espacio, 30 "peceando"<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiK4rpyixz3GSoiYmR4M5AGniFV43av8_xxHBamsoQ1lU8UDdV2bWOAEcIbXLn9Y4VgDc-hfTgc94F_5q1bgJuJfacvY0swDxVbULpc9Aiq8_9w58wPribzCY4hrX_-z-SV1xaQpUCnGjs/s200/320px-IBM_PC_5150.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="144" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiK4rpyixz3GSoiYmR4M5AGniFV43av8_xxHBamsoQ1lU8UDdV2bWOAEcIbXLn9Y4VgDc-hfTgc94F_5q1bgJuJfacvY0swDxVbULpc9Aiq8_9w58wPribzCY4hrX_-z-SV1xaQpUCnGjs/s200/320px-IBM_PC_5150.jpg" width="200" /></a></div>
<div style="text-align: right;">
<br />
<blockquote>
<span style="font-family: tahoma;"><i>640K ought to be enough for anybody.</i></span></blockquote>
</div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">- Bill Gates, 1981 (*)</span></div>
<br />
Una cosa es segura: en tecnología no se deberían realizar aseveraciones del tipo "nunca jamás" porque más tarde o más temprano, el tozudo paso del tiempo te acabará poniendo en el ridículo más espantoso.<br />
<br />
Hace 30 años, se lanzó el IBM PC, predecesor de los actuales ordenadores personales que hay en la mayoría de las casas y oficinas. Curioso nombre el que le pusieron, ya que difícilmente se podría llamar "personal" a algo científico que podía costar hasta casi $20.000, aunque mira tú, ironías del destino, sus equipos sucesores si han acabado siendo "personales".<br />
<br />
Con respecto a los temas de tecnología que vertebran este blog, de este año destacaría otro suceso trascendental aparte de la curiosa efeméride anterior: un fallecimiento. Este año nos dejó una de las personas que más relevancia tiene en prácticamente toda la tecnología que uso diariamente en mi profesión y de la que deriva la esencia de casi todo lo que usamos: Dennis MacAlistair Ritchie, más conocido como <b>Dennis Ritchie</b>, o simplemente <b><span style="font-family: "Courier New",Courier,monospace;">dmr</span></b> (muchas veces escrito así, "dmr", en minúsculas, con un tremendo respeto, y con la solemnidad con la que uno escribe la más valiosa contraseña). El azar ha querido que el año de su muerte sea también el 40 aniversario de la publicación del primer manual de <b>UNIX</b> "UNIX Programmer’s Manual" que él escribió conjuntamente con <b>Ken Thomson</b>.<br />
<br />
Poco puedo añadir yo a lo muchísimo publicado sobre quién fue dmr. La mayor parte de los que visitáis el blog con asiduidad, conocéis su enorme y extensísima contribución al mundo. Tan enorme, como igual de decepcionante la poca repercusión que la noticia ha tenido en la prensa no especializada, que sin embargo ha dado extensa cobertura a otro lamentable fallecimiento contemporáneo, de un personaje más público y notorio, más <i>cool</i>, aunque su legado no pueda ser comparable en absoluto ni por transcendencia ni por importancia. El tiempo pondrá a cada uno en su sitio.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl2cmYD2cd3Fxj0_t-gI-b7EsNhruciDdG1sAZlIjuONa66ezZiEuR2lzCMbamuV1wCDneTmkoDhCP0N4N3vWlvHrgHBOkPmGLHsi67hmEfZ48XvnwBTRaEpCNJHF9z5aaI6Gk72Cack8/s1600/goodbye.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl2cmYD2cd3Fxj0_t-gI-b7EsNhruciDdG1sAZlIjuONa66ezZiEuR2lzCMbamuV1wCDneTmkoDhCP0N4N3vWlvHrgHBOkPmGLHsi67hmEfZ48XvnwBTRaEpCNJHF9z5aaI6Gk72Cack8/s320/goodbye.jpg" width="320" /></a></div>
<br />
La significación en el mundo de la tecnología de dmr es comparable a la de Marie Curie a la física nuclear o la de Ramón y Cajal a la neurología... y aún así, hay una diferencia extrema: mientras éstos "descubrieron", dmr creó. dmr puso las dos semillas de los llamados entonces Sistemas Abiertos con la creación de UNIX y C. De la misma forma que no podríamos hablar del ADN sin la adenina, guanina, y citosina, tampoco podríamos hablar de Windows, Linux, Mac OS X, Java, Ruby, PHP, o .NET sin C, ya que C ha sido y sigue siendo la base de la creación tecnológica a partir de la cual se han construido tecnologías más complejas.<br />
<br />
Por otro lado, Internet (correo electrónico, facebook, Google, twitter, etc), Android, Mac OS X, iPhone y su iOS, Linux... todos tienen en común su procedencia y su esencia, su corazón: el UNIX que creó dmr. Actualmente, desde los Sistemas Operativos de los más grandes e importantes Data Centers y de los equipos financieros del mundo, hasta los smartphones más pequeños siguen usando algún tipo de UNIX o una derivación de éste. Sobre UNIX y C está construido el mundo tecnológico que conocemos. Este es el enorme legado de dmr.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"><tbody>
<tr><td style="text-align: center;"><a href="http://apod.nasa.gov/apod/ap110608.html" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2SWgJgPwKvjTwVOBnyM3Pod4VSZW_KxjT7Y5tyO5WGJt6U9ufJ6oehZyaPybV58gCwsj66n6atYemhEl0kdx8P4-rvwseXczcffTN9_Ks1zTDBIL7tcKFsCX4JhCbmIdZp49tpBKKu9g/s320/shuttleiss_nasa_900.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Transborador y Estación Espacial Internacional juntas<br />
Fuente:
<a href="http://www.nasa.gov/">NASA</a></td></tr>
</tbody></table>
En otro orden de cosas, de interés también de este blog, damos repaso al año en lo que a temas de astronomía se refiere: 30 años después del primer vuelo orbital de un transbordador espacial (el <a href="http://es.wikipedia.org/wiki/Transbordador_espacial_Columbia">Columbia</a>), este año se ha puesto <a href="http://es.wikinews.org/wiki/El_Atlantis_pone_fin_a_la_era_de_los_transbordadores_espaciales">fin al programa de transbordadores espaciales</a>, es decir, al <a href="http://es.wikipedia.org/wiki/Transbordador_STS">programa STS</a>. La sobrecogedora foto a la izquierda, es muy especial. Por lo general se toman fotografías de la Estación Espacial Internacional (<a href="http://es.wikipedia.org/wiki/Estaci%C3%B3n_Espacial_Internacional">ISS</a>) desde el transbordador, o viceversa, pero no es frecuente que una tercera nave esté acercándose mientras las dos anteriores están unidas. Esta imponente imagen, tomada desde una nave <a href="http://es.wikipedia.org/wiki/Soyuz_TMA-20">Soyuz TMA-20</a>, donde se aprecia el enorme tamaño de la Estación Espacial Internacional, es una preciosa foto que no se podrá volver a tomar nunca más. <br />
<br />
Coincide este hecho con la celebración del 50 aniversario del primer vuelo espacial, realizado por <b>Yuri Alexéievich Gagarin</b>, ciudadano soviético, a bordo de la nave <b>Vostok 1</b>. En honor a su viaje y su transcendencia, la ONU decidió declarar el 12 de Abril como "Dia del Espacio". Esa misma noche se celebra la "<b><i><a href="http://es.wikipedia.org/wiki/La_noche_de_Yuri">noche de Yuri</a></i></b>". Curiosamente, el día del primer vuelo de un transbordador orbital (Columbia) fue también el 12 de Abril.<br />
<br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxSscnQqtlAQRDu9IOMr7zQ1wItB4u6eKowUpdiFApswHw7xz5S2Vg5rAIzj4t6-PC4_oVEBbmcYgcmxFluYlJW2pdOVA2gcYhH7nporyYnQooXZAk9nSSgyJIpHkyBb6lWtIAN8MsqHw/s1600/sagan.jpg" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="106" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxSscnQqtlAQRDu9IOMr7zQ1wItB4u6eKowUpdiFApswHw7xz5S2Vg5rAIzj4t6-PC4_oVEBbmcYgcmxFluYlJW2pdOVA2gcYhH7nporyYnQooXZAk9nSSgyJIpHkyBb6lWtIAN8MsqHw/s200/sagan.jpg" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Carl Sagan</td></tr>
</tbody></table>
También el 20 de diciembre de este año se cumplen <a href="http://www.elmundo.es/elmundo/2011/12/19/ciencia/1324316030.html">15 años sin el divulgador científico más grande de todos los tiempos</a>. El "astrónomo del pueblo" que ilusionó a todas las mentes inquietas a través de una narración elocuente, precisa, seductora y poética en "<a href="http://es.wikipedia.org/wiki/Cosmos:_Un_viaje_personal"><i>Cosmos: un viaje personal</i></a>": <a href="http://es.wikipedia.org/wiki/Carl_Sagan">Carl Sagan</a>.<br />
<br />
Termino con un comienzo esperanzador, una emocionante nueva misión con el robot de exploración espacial más sofisticado lanzado hasta ahora: el <a href="http://es.wikipedia.org/wiki/Curiosity">Curiosity</a>. Os dejo con una animación de su viaje, su espectacular aterrizaje y operaciones de superficie (ponedlo a pantalla completa en HD porque merece la pena).<br />
<br />
¡ Feliz nuevo año 2012 !<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.youtube.com/embed/P4boyXQuUIw?feature=player_embedded' frameborder='0'></iframe></div>
<br />
<br />
<br />
(*) La frase ha sido atribuida frecuentemente a Bill Gates, aunque <a href="http://imranontech.com/2007/02/20/did-bill-gates-say-the-640k-line/">él ha negado decir tal cosa</a> y existe <a href="http://en.wikiquote.org/wiki/Talk:Bill_Gates">discusión</a> al respecto ya que no parecen existir evidencias firmes.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://es.wikipedia.org/wiki/Dennis_Ritchie">Dennis Ritchie</a> </li>
<li><a href="http://alt1040.com/2011/10/dennis-ritchie-que-seria-del-mundo-sin-su-legado">Dennis Ritchie y su legado inmenso</a> </li>
<li><a href="http://www.enter.co/historia-2/muere-dennis-ritchie-el-creador-del-lenguaje-de-programacion-c/">Se despide otro titán tecnológico: Dennis Ritchie, padre de C y UNIX</a></li>
<li><a href="http://es.wikipedia.org/wiki/Yuri_Gagarin">Yuri Gagarin</a></li>
<li><a href="http://www.youtube.com/watch?feature=player_detailpage&v=x1gmvOeeL78">Documental sobre la vida de Carl Sagan</a> </li>
<li><a href="http://danielmarin.blogspot.com/2011/11/curiosity-el-robot-marciano-mas.html">Curiosity: el robot marciano más complejo de la historia</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-20850136000949746552011-12-14T02:01:00.000+01:002012-02-02T19:53:26.635+01:00Copiar y pegar en applets Java<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmKbd9WkmRkxMgkSlbA8HROfLgFw-Id3D9iMjuHoNp1G9Rf_91ojvMaqGFxZFthwrZOyH4HTXvSnB0H3vgOLrdxseHO52-QOUBwld23u9qR7XHO2gYZSZW5tjeXA_kJEqw-Kg8uI-fj60/s200/Bubble_Gums__28_.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmKbd9WkmRkxMgkSlbA8HROfLgFw-Id3D9iMjuHoNp1G9Rf_91ojvMaqGFxZFthwrZOyH4HTXvSnB0H3vgOLrdxseHO52-QOUBwld23u9qR7XHO2gYZSZW5tjeXA_kJEqw-Kg8uI-fj60/s200/Bubble_Gums__28_.jpeg" width="200" /></a>Una de las páginas a las que suelo acceder a menudo es <a href="http://www.cis.upenn.edu/%7Ematuszek/General/RegexTester/regex-tester.html">ésta</a>. Se trata de una sencilla página contenedora de un applet para probar expresiones regulares en Java realizada por <b>David Matuszek</b>.<br />
<br />
Esta página contiene una de ésas maravillosas utilidades tipo que acaban siendo atemporales (yo diría que hace más de 7 años que lo uso): sencilla, directa, concisa y eficaz. La verdad es que para probar una expresión regular antes de incorporarla en el código no se necesita más de eso... ni menos tampoco, ya que esto permite ahorrar mucho tiempo de depuración. Una pequeña joya muy recomendable.<br />
<br />
<br />
De un tiempo a esta parte, me di cuenta que ya no podía copiar las expresiones realizadas ni pegar texto de ejemplo. Esto me resultaba tremendamente molesto, pero siempre que usaba la página tenía tanta prisa por resolver el problema que me llevaba a ella que no me permitía detenerme un momento para averiguar la razón del incómodo cambio.<br />
<br />
Bueno, pues resulta que desde el lanzamiento de Java Plug-in 1.6.0_24 en Febrero 2011, copiar y pegar desde o hacia el portapapeles del sistema se consideró un agujero de seguridad y, por tanto, se desactivó. Puedes copiar <i>entre</i> applets, pero no entre applet y portapapeles del sistema.<br />
<br />
La solución estaría en modificar el fichero java.policy del directorio lib/security del plugin, aunque lo más probable es que este cambio sea sobreescrito de nuevo en la siguiente actualización de la JRE. Así que lo mejor es crear un archivo de usuario java.policy personalizado:<br />
<ol>
<li>Localiza tu fichero <i>Java Security Policy</i>. Se llama java.policy y debería estar bajo el directoro lib/security de tu instalación Java JRE. En Linux está en /usr/lib/jvm/java-6-sun-1.6.0.26/jre/lib/security/java.policy.</li>
<li> Copialo a tu home y renómbralo a <span style="font-family: "Courier New",Courier,monospace;">.java.policy</span> (fíjate que debe comenzar con un punto).</li>
<li>Edita el fichero y añade la línea que se indica debajo de los comentarios:</li>
<pre class="brush:java; gutter: false;">// "standard" properties that can be read by anyone
permission java.awt.AWTPermission "accessClipboard";
</pre>
<li>Reinicia el navegador</li>
</ol>
<sun-ejb-jar></sun-ejb-jar><br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.cis.upenn.edu/%7Ematuszek/General/RegexTester/regex-tester.html">Regular Expression Test Applet</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-2212552917622111722011-11-12T16:30:00.000+01:002011-11-14T00:17:37.674+01:00Los niveles de aislamiento en PostgreSQL (no son 4)<br />
<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjisKDYPR4cD5wmpjSjrxIZwD4T0UTwYpnyDFbRq3hCGl8hROtRTVoRoSsRZzZqhXnG4HX0EjXrj7ZhbqjQa71DOfOre3eul3YJBAzJVNpOFrHHXGHG6fJrtN13sMd-wf1ZM14Ghd-jhX4/s200/n%25C3%25BAmeros.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjisKDYPR4cD5wmpjSjrxIZwD4T0UTwYpnyDFbRq3hCGl8hROtRTVoRoSsRZzZqhXnG4HX0EjXrj7ZhbqjQa71DOfOre3eul3YJBAzJVNpOFrHHXGHG6fJrtN13sMd-wf1ZM14Ghd-jhX4/s200/n%25C3%25BAmeros.png" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>"No. No lo intentes. Hazlo, o no lo hagas, pero no lo intentes."</i></span></blockquote>
</div>
<div align="right">
- <span style="font-family: tahoma; font-size: x-small;"><a href="http://es.wikipedia.org/wiki/Yoda">Maestro Yoda</a></span></div>
<br />
Cuando ví el Episodio IV de la Guerra de las Galaxias ("El Imperio Contraataca"), aún era un niño impresionable, y me llamó la atención la reprenda que hizo Yoda a Luke y que cito aquí. Era uno de ésos consejos marciales que se enuncian solemnes como un consejo vital.<br />
<br />
Con el tiempo te das cuenta que como consejo está bien, y puede ser incluso un buen objetivo... pero en ciertas facetas de la vida no es válido. Por ejemplo, en el mundo científico y en nuestro mundo profesional el consejo es justamente el contrario: inténtalo, pruébalo y compruébalo. Y sólo cuando lo hayas hecho y consigas un resultado repetible, ponlo en práctica, esto es, <i>súbelo a producción</i>.<br />
<br />
Gracias a no seguir el consejo de Yoda fui consciente de una (grave) carencia de PostgreSQL con respecto a los niveles de aislamiento. Como <a href="http://balteus.blogspot.com/2010/10/control-del-nivel-de-aislamiento.html">ya hice una introducción al aislamiento en otro artículo</a>, no voy a extenderme más en el tema y voy al grano. El caso que me ocupaba es que tenía que hacer una importación transaccional de datos masiva en un sistema en OLTP de producción en el que se están modificando constantemente datos relacionados con los que voy a importar. El resultado de la importación es que la transacción gigante bloquea datos e impide que se efectúen modificaciones en datos relacionados paralizando en la práctica buena parte de las operaciones de producción produciéndose un efecto "bola de nieve" al sumarse cada vez más transacciones en cola a la transacción gigante pendiente. Sin embargo, para lo único que quiero la transacción es para tener atomicidad en la operación, es decir, para que no se quede a medias en caso de algún problema, pero no me importa que se puedan producir eventualmente casos de <i>dirty read</i>, que no afectarían a los usuarios del sistema de producción en su trabajo. Vale, no hay problema. La transacción de inserción la podemos realizar con el nivel de aislamiento más bajo (READ_UNCOMMITED) y problema solucionado. ¿No? No obstante, no hagamos caso a Yoda, y probémoslo en pre-producción. Resultado: exactamente el mismo que si no hubiera especificado nada del nivel de aislamiento.<br />
<br />
¿Qué ha pasado? <br />
<br />
En la <a href="http://www.postgresql.org/docs/9.0/static/sql-set-transaction.html">documentación de SET TRANSACTION</a>, en efecto compruebo que PostgreSQL admite los cuatro niveles de aislamiento como la mayoría de las bases de datos (de hecho, la sentencia no dio error)... pero sólo sintácticamente: no están todos implementados. Si contiúas leyendo te das cuenta que no son 4, sino 2 los niveles implementados:<br />
<blockquote class="tr_bq" style="background-color: #f3f3f3; color: blue;">
"The SQL standard defines two additional levels, <tt class="LITERAL">READ UNCOMMITTED</tt> and <tt class="LITERAL">REPEATABLE READ</tt>. In <span class="PRODUCTNAME">PostgreSQL</span> <tt class="LITERAL">READ UNCOMMITTED</tt> is treated as <tt class="LITERAL">READ COMMITTED</tt>, while <tt class="LITERAL">REPEATABLE READ</tt> is treated as <tt class="LITERAL">SERIALIZABLE</tt>."</blockquote>
Lo que viene a decir: "<i>¿Pensabas que eran cuatro, no? Pues no. Son dos</i>". De hecho, ahora (con la versión 9.1) ya son 3. Pero sigue sin estar soportada la <i>lectura sucia</i> (<i>dirty read</i>). En la <a href="http://www.postgresql.org/docs/9.0/static/transaction-iso.html">documentación sobre aislamiento</a> también es bastante claro:<br />
<blockquote class="tr_bq" style="background-color: #f3f3f3; color: blue;">
"In <span class="PRODUCTNAME">PostgreSQL</span>, you can request any of
the four standard transaction isolation levels. But internally,<b>
there are only two distinct isolation levels</b>, which correspond to
the levels Read Committed and Serializable. When you select the
level Read Uncommitted you really get Read Committed, and when you
select Repeatable Read you really get Serializable, so the actual
isolation level might be stricter than what you select."</blockquote>
<br />
Un verdadero jarro de agua a mis pretensiones, ya que no puedo conseguir atomicidad sin bloqueo (aunque sea realizando lecturas de transacciones no confirmadas) en PostgreSQL, al menos con la versión actual 9.1.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.postgresql.org/docs/9.0/static/transaction-iso.html">Transaction Isolation (Documentación de PostgreSQL 9.0) (2 Niveles)</a></li>
<li><a href="http://www.postgresql.org/docs/9.0/static/sql-set-transaction.html">SET TRANSACTION (Documentación de PostgreSQL 9.0) (2 Niveles)</a></li>
<li><a href="http://www.postgresql.org/docs/9.1/static/transaction-iso.html">Transaction Isolation (Documentación de PostgreSQL 9.1) (3 Niveles)</a><br />
</li>
<li><a href="http://www.postgresql.org/docs/9.1/static/sql-set-transaction.html">SET TRANSACTION (Documentación de PostgreSQL 9.1) (3 Niveles)</a> </li>
</ul>
<br />
<ul></ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com4tag:blogger.com,1999:blog-1763183641342103044.post-39132595661563452142011-10-27T23:15:00.000+02:002012-02-07T01:03:59.444+01:00Generar certificados autofirmados con OpenSSL<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo9Y3IUDncvHaryMhhPLIU2YJu2h7on2RZ3T2NDdf046Z8gCr7rPVAc8iuKYsW7fZNKtUPAFLoW4TezMu0sxC-X3X4YA7a3_r0VM2Sm-sfSW1bwl31FMuPi-YzO4gx2HwFksdW4g7M0Hc/s1600/openssh_logo.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgo9Y3IUDncvHaryMhhPLIU2YJu2h7on2RZ3T2NDdf046Z8gCr7rPVAc8iuKYsW7fZNKtUPAFLoW4TezMu0sxC-X3X4YA7a3_r0VM2Sm-sfSW1bwl31FMuPi-YzO4gx2HwFksdW4g7M0Hc/s1600/openssh_logo.jpg" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>Software is like sex: It’s better when it’s free.</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">Linus Torvalds.</span></div>
<br />
<br />
Tengo la suerte de trabajar en un lugar rodeado de extraordinarios profesionales como compañeros. El artículo que traigo aquí hoy es un resumen de un correo electrónico de uno de ellos que, con su permiso (y sugerencia) he convertido humildemente en otro post más para este blog. Gracias, Josete. Es un placer y un honor trabajar contigo.<br />
<br />
<br />
<br />
<h2>
<span style="color: #7f6000;">Mini How-To: Generar certificados autofirmados con OpenSSL para Apache HTTP Server</span></h2>
<div style="text-align: right;">
<span style="font-size: small;">-por José Morales Mora.</span></div>
<br />
<h3>
PASO 1. Generar Clave RSA</h3>
Ejecutar:<br />
<br />
<pre class="brush: bash; gutter: false;">openssl genrsa -des3 -out server.key 1024</pre>
<br />
Genera una clave CA para realizar la firma del certificado.
Nos pide la clave privada para este certificado. Podemos especificar el tamaño de la clave ( 1024, 2048)<br />
<br />
<h3>
PASO 2. Generar CSR ( Petición de Firma de Certificado)</h3>
Ejecutar:<br />
<br />
<pre class="brush: bash; gutter: false;">openssl req -new -key server.key -out server.csr</pre>
<br />
Realiza una petición para la firma con clave privada especificado. Al realizarlo nos pide datos:<br />
<br />
<pre class="brush: text; gutter: false;">Country Name (2 letter code) []:
State or Province Name (full name) []:
Locality Name (eg, city) []:
Organization Name (eg, company) []:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:</pre>
<pre class="brush: text; gutter: false;"> </pre>
<pre class="brush: text; gutter: false;"></pre>
<b>IMPORTANTE:</b> El <i>"Common Name"</i> debe corresponder con la URL que queremos Securizar. Si la URL a poner por SSL es www.paco.es, este campo debe contener exactamente eso.<br />
<br />
<br />
<h3>
PASO 3. Eliminar Clave Privada DES3</h3>
Ejecutar:<br />
<br />
<pre class="brush: bash; gutter: false;">cp server.key server.key.org
openssl rsa -in server.key.org -out server.key
</pre>
<br />
Esto es necesario porque en estos casos que tenemos un certificado firmado con clave primaria, Apache HTTP Server pide en cada arranque esa clave para utilizar el certificado.
La solución es eliminar la encriptación DES3 para la clave.<br />
<br />
<br />
<h3>
PASO 4 . Generar Certificado Autofirmado.</h3>
Ejecutar:<br />
<br />
<pre class="brush: bash; gutter: false;">openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt</pre>
<br />
Con este paso obtenemos el CRT autofirmado preparado para ser utilizado en apache.<br />
<br />
<h3>
PASO 5. Configurar Apache</h3>
Para utilizar estos certificados en apache, lo que tenemos que hacer es añadir al Virtual Host que queramos:<br />
<br />
<pre class="brush: text; gutter: false;">SSLEngine on
SSLCertificateFile /usr/local/apache/conf/ssl.crt/server.crt
SSLCertificateKeyFile /usr/local/apache/conf/ssl.key/server.key
</pre>
<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.openssh.com/">OpenSSH</a></li>
<li><a href="http://httpd.apache.org/">Apache HTTP Server</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com3tag:blogger.com,1999:blog-1763183641342103044.post-45807567822932448062011-10-09T23:57:00.000+02:002012-02-07T01:02:13.104+01:00Combinando XPath con JAXB<div style="text-align: right;">
<div style="text-align: left;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXHN4NDk5fAt1BxJNMD9_69dUFHt6rHtktibWsj8N-UeoLfC9IZ3p-zVR6-9nePE0iJJSxYXiyIxL5wT76rw5ayZmTO-C-Dl-r79GYoD8j5aG9O-z5BYLEJzekAHXy84MleOgjl_G5NHY/s200/lupa400.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXHN4NDk5fAt1BxJNMD9_69dUFHt6rHtktibWsj8N-UeoLfC9IZ3p-zVR6-9nePE0iJJSxYXiyIxL5wT76rw5ayZmTO-C-Dl-r79GYoD8j5aG9O-z5BYLEJzekAHXy84MleOgjl_G5NHY/s200/lupa400.jpeg" width="200" /></a></div>
<span style="font-family: tahoma;">
</span><br />
<blockquote>
<span style="font-family: tahoma;"><i>El primer 90% del código ocupa el 90% del tiempo de desarrollo. El 10% restante del código ocupa el otro 90% de tiempo de desarrollo.</i></span></blockquote>
<span style="font-family: tahoma;">
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;"><a href="http://es.wikipedia.org/wiki/Regla_del_noventa-noventa">Regla del noventa-noventa</a>, Tom Cargill.</span></div>
<br />
<br />
Usar JAXB es tremendamente cómodo si tenemos que procesar datos XML bien definidos y cuya estructura sea bastante estable en el tiempo: nos evitamos toda la fontanería de análisis, verificación y <a href="http://en.wikipedia.org/wiki/Marshalling_%28computer_science%29">marshalling / unmarshalling</a>. Por otro lado, nos resuelve de un plumazo convertir los datos XML a objetos <a href="http://en.wikipedia.org/wiki/Data_transfer_object">DTO/VO</a> de datos en nuestra aplicación ya que nos permitirá pasarlos directamente a Servicios de negocio o a <i>vista</i> (si usamos un <a href="http://es.wikipedia.org/wiki/Modelo_Vista_Controlador">MVC</a>), en lugar de crearlos y mantenerlos manualmente cada vez que se modifican las especificaciones.<br />
<br />
Pero no todo son ventajas. A la hora de acceder a un dato de un elemento, tratar con objetos puede suponer un verdadero engorro de iteraciones anidadas o tener que usar predicados para las colecciones de elementos, cuando con <a href="http://es.wikipedia.org/wiki/XPath">XPath</a> podemos realizar un acceso rápido y directo al elemento a través de sencillas expresiones.<br />
<br />
Por ejemplo, supongamos que tenemos el siguiente XML:
<br />
<pre class="brush:xml; gutter: false;"> <empleados>
<empleado>
<id>1</id>
<direcciones>
<direccion>
...
<cp>06002</cp>
</direccion>
</direcciones>
</empleado>
<empleado>
<id>2</id>
<direcciones>
<direccion>
...
<cp>28034</cp>
</direccion>
</direcciones>
</empleado>
<empleado>
<id>3</id>
<direcciones>
<direccion>
...
<cp>06002</cp>
</direccion>
</direcciones>
</empleado>
</empleados>
</pre>
Si necesitamos acceder a todos los elementos/objetos <span style="font-family: "Courier New",Courier,monospace;">empleado</span> cuyo elemento <span style="font-family: "Courier New",Courier,monospace;">cp</span> sea <span style="font-family: "Courier New",Courier,monospace;">06002</span>, usando objetos generados por JAXB deberíamos iterar por la colección <span style="font-family: "Courier New",Courier,monospace;">empleados</span>, así:<br />
<br />
<pre class="brush:java; gutter: false;">List<Empleado> empleados06 = new ArrayList<Empleado>();
for ( Empleado empleado : empleados.getEmpleadoList() ) {
for ( direccion : empleado.getDirecciones().getDireccionList() ) {
if ( direccion.getCp().equals("06002") ) {
empleados06.add(empleado);
}
}
}
</pre>
<br />
con XPath es mucho más simple: podemos obtener una lista usando la expresión<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">//empleado[cp='06002']</span> <br />
<br />
Cuanto más niveles jerárquicos tenga nuestro árbol de información (más grados de anidación), más compleja se hace la recuperación de datos usando JAXB. Sin embargo, con XPath es tan simple como evaluar una expresión.<br />
<br />
Hasta que descubrí JXPath, tenía que elegir entre XPath (y pagar la
"penalización" de realizar el marshalling/unmarshalling manualmente) o
JAXB (y pagar la penalización de la selección de elementos con código
manual). <br />
<br />
<h4>
JXPath</h4>
JXPath es otro genial componente de Apache Commons: una librería que evalúa expresiones (basadas en) XPath contra jerarquías de objetos Java, permitiendo hacer complejas consultas e iteraciones sobre estructuras y conjuntos de simples objetos <a href="http://es.wikipedia.org/wiki/Plain_Old_Java_Object">POJO</a>.<br />
<br />
Es decir, te permite usar XPath sobre objetos. Y no sólo sobre objetos serializados vía JAXB, sino cualquier POJO o colección de éstos. Si XPath es al XML lo que el SQL a las bases de datos, JXPath es el equivalente a los objetos Java. Es la solución perfecta para simplificar código que debe evaluar y filtrar conjuntos de objetos o, por ejemplo, cuando debemos seleccionar datos en objetos en tiempo de ejecución, en los que es sencillo construir una expresión XPath dinámica. El artículo <a href="http://today.java.net/pub/a/today/2006/08/03/java-object-querying-using-jxpath.html">"<i>Java Object Querying Using JXPath</i>"</a>, muestra una serie de ejemplos muy ilustrativos.<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://commons.apache.org/jxpath/">JXPath</a></li>
<li><a href="http://today.java.net/pub/a/today/2006/08/03/java-object-querying-using-jxpath.html">Java Object Querying Using JXPath</a> </li>
<li><a href="http://www.tfo-eservices.eu/wb_tutorials/media/JXPathTutorial/PDF/JXpathTutorial.pdf">JXPath Tutorial (pdf)</a></li>
<li><a href="http://www.javaworld.com/javaworld/jw-03-2007/jw-03-jxpath.html">Java object queries using JXPath</a></li>
<li><a href="http://www.oracle.com/technetwork/articles/javase/index-140168.html">Java Architecture for XML Binding (JAXB)</a> </li>
<li><a href="http://es.wikipedia.org/wiki/XPath">XPath</a></li>
<li><a href="http://balteus.blogspot.com/2009/09/banco-de-experiencias-iv-librerias.html">Banco de experiencias (IV): librerías imprescindibles en Java</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0tag:blogger.com,1999:blog-1763183641342103044.post-905409695286288542011-09-13T11:36:00.001+02:002011-09-14T10:48:26.050+02:00Sincronización de llamadas a Webservices y EJB<div style="text-align: right;">
<div style="text-align: left;">
<a href="http://xkcd.com/764/" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTSfyHcb9jWJT-Q4pbHeJHNtcDIQMg6SUctHnEr9bS6NOG1IoCmiodW5yGBnWpgmC5j-D1L_WNLHVR2GoDO7O7SwDylvZyY6girPG260xqfHOzH5kVW0rprUZS20mcn7-3szMTeNuPeF0/s200/one_two.png" width="200" /></a></div>
<span style="font-family: tahoma;">
<blockquote>
<i>A la vista de suficientes ojos, todos los errores resultan evidentes.</i></blockquote>
</span></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;"><a href="http://es.wikipedia.org/wiki/Ley_de_Linus">Ley de Linus</a>, formulada por Linus Torvalds, (1997).</span></div>
<br />
Los servidores de aplicaciones y la arquitectura J2EE fue diseñada desde el principio con el multithreading en mente. La idea de escalabilidad y procesamiento paralelo de forma segura ha sido en una constante en su desarrollo y evolución para que los desarrolladores pudiéramos construir aplicaciones seguras sin preocuparnos de asuntos como la gestión de memoria o la sincronización de objetos.<br />
<br />
Sin embargo, para las aplicaciones "de la vida real" nos encontramos con que algunas veces tenemos que "<i>serializar</i>" (en el sentido de alinear poniendo en serie, encolar manteniendo un orden y como contraposición al procesamiento paralelo) llamadas o procesamientos concretos... Algo para lo que J2EE no fue pensado desde el principio. Así, en el diseño y construcción de aplicaciones empresariales se suelen dar una serie de necesidades relacionadas entre si que, hasta hace poco, no han tenido solución directa manejada en el estándar JEE:<br />
<ul>
<li><u>Serialización o sincronización de procesamiento de peticiones de un webservice</u>. Es decir, poder hacer un WebService como si fuese un Servlet <a href="http://download.oracle.com/javaee/5/api/javax/servlet/SingleThreadModel.html">SingleThreadModel</a> (ya obsoleto, por cierto). En definitiva: garantizar que no se atiende otra petición mientras se está atendiendo ya una, evitando la simultaneidad y por tanto evitando también duplicidad de procesamientos realizada por un cliente demasiado <i>impaciente</i>.</li>
<li><u>Serialización o proceso ordenado de los mensajes de una cola JMS</u> o, lo que es lo mismo, mantenimiento del orden de llegada en el procesamiento de los mensajes. Esto, que podría parecer obvio, no lo es tanto, ya que para un MDB (Message Driven Bean), el contenedor crea un pool de objetos que trabajan en paralelo de forma que si se sacan 2 o 4 mensajes simultáneamente, puede ser que un mensaje más reciente se tarde menos en procesar que un mensaje anterior.</li>
<li>Instanciación de un <a href="http://en.wikipedia.org/wiki/Singleton_pattern">singleton</a>, patrón en principio no permitido por la especificación J2EE (hasta la reciente EJB 3.1, de la que hablaré más adelante). El patrón singleton es tremendamente necesario para asegurar la instanciación única de motores o manejadores de objetos (conexiones, datos, cachés, clientes, etc) que deben estar perfectamente sincronizados.</li>
</ul>
El que no haya tenido que solucionar este problema podrá pensar que nada más fácil como especificar al servidor que instancie un pool de tamaño 1 para el EJB/MDB que queramos y, <i>voilà</i>, problema solucionado. La idea es buena. Si aseguramos una y sólo una exclusiva y única instancia de nuestro EJB, podemos resolver las tres necesidades de un sólo plumazo: podríamos publicar dicho EJB como un Webservice, tener un sólo MDB o tener nuestro Singleton.... Por ejemplo, en el caso de Glassfish, podríamos indicarlo en el correspondiente fichero sun-ejb-jar.xml, de la siguiente forma:<br />
<br />
<pre class="brush:xml; gutter: false;"><sun-ejb-jar>
<enterprise-beans>
<ejb>
<ejb-name>DataProviderService</ejb-name>
<bean-pool>
<steady-pool-size>1</steady-pool-size>
<resize-quantity>1</resize-quantity>
<max-pool-size>1</max-pool-size>
<pool-idle-timeout-in-seconds>0</pool-idle-timeout-in-seconds>
</bean-pool>
</ejb>
</enterprise-beans>
</sun-ejb-jar>
</pre>
<br />
<br />
Pero lamentablemente no es así: <b>no funciona</b>. Al menos en Weblogic, Glassfish y JBoss. Dudo que eso sea posible en ninguno. La razón es sencilla: el contenedor no está diseñado para eso, sino justamente para lo contrario, con lo que conseguiremos un nivel altísimo de reciclado de instancias, pero no conseguiremos mantener la misma instancia de forma permanente sin que la recicle el servidor. Tampoco haciendo variaciones con esos parámetros. Tras un número suficiente de pruebas comprobaremos que el servidor recicla y mantiene, aunque sea durante pocos instantes, varias instancias del mismo EJB.<br />
<br />
<h3>
Las soluciones</h3>
En principio hay tres soluciones válidas.<br />
<br />
Si estás usando JEE 5 o inferior, es decir, un contenedor EJB 3.0 o inferior, tienes dos soluciones a tu alcance que básicamente pasan por mantener la sincronización <i>fuera</i> del servidor de aplicaciones: crear un JMX MBean o sincronizar por tu cuenta. Si estás usando JEE 6, estás de enhorabuena. Aquí están mis propuestas.<br />
<br />
<b>Usar un MBean de <a href="http://es.wikipedia.org/wiki/Java_Management_Extensions">JMX</a></b><br />
Un MBean es, en definitiva, un singleton accesible vía JMX. No es un objeto manejado por el contenedor de EJB ni un estándar JEE, pero es una solución más elegante que realizar un Singleton por código ya que podemos controlar su ciclo de vida e incluso acceder a su estado de manera remota. Eso si, como decía, la sincronización de los objetos que use (colas JMS, etc) corre por nuestra cuenta. El problema del WebService lo podemos reducir a un problema de JMS, ya que podríamos publicar los mensajes en una cola y extraerlos uno a uno haciendo que nuestro MBean sea un cliente JMS.<br />
<br />
<b>Usar un recurso sincronizable</b><br />
Un mismo EJB puede ejecutarse en diferentes JVM's. El ciclo de vida de los objetos y su concurrencia es cosa del contenedor. Por tanto, declarar un método de un EJB como "synchronized" es una violación de la especificación y no debería ser una opción. Por tanto, nuestros EJB's deberán usar un objeto manejado que pueda ser sincronizado: bien un Singleton propio (si nos basta con sincronizar para una única JVM), bien usando la transacciones serializables de base de datos (si necesitamos sincronizar entre varias JVM's o queremos hacerlo más escalable).<br />
<br />
<b>Crear un Singleton Session Bean</b><br />
Si puedes usar un contenedor JEE 6 compatible, puedes implementar un <a href="http://download.oracle.com/javaee/6/tutorial/doc/gipvi.html">Singleton Session Bean</a>. Ésta es por fin la solución adecuada dentro del estándar JEE: un singleton manejado con atributos para controlar la sincronización. Con este método se solucionan de un plumazo todas las cuestiones de sincronización o singletons de una forma segura y manejada por parte del contenedor EJB.<br />
<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://download.oracle.com/javase/6/docs/technotes/guides/jmx/index.html">Java Management Extensions (JMX) Technology</a></li>
<li><a href="http://www.dosideas.com/noticias/java/528-ejb-31-un-paso-importante-hacia-la-madurez.html">EJB 3.1: un paso importante hacia la madurez</a></li>
<li><a href="http://www.ibm.com/developerworks/java/library/j-dcl/index.html">Double-checked locking and the Singleton pattern</a></li>
<li><a href="http://java.sun.com/developer/technicalArticles/Programming/singletons/">When is a Singleton not a Singleton?</a></li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com2tag:blogger.com,1999:blog-1763183641342103044.post-24394549106346630542011-07-28T14:42:00.003+02:002011-07-29T09:06:35.900+02:00Cambiar la URL de conexión y establecer timeout a un Web Service JAX-WS<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBWoOWsezpptYqxOuVjfBUBPB9jNoM3ovdaNztw9aQ12N5qZqmeEYWsr5BDAatO2Crmy0UZY1k2XDXehMuV3WGW7C6XEZsxeap2t6xSeVMK8IAOrISZgceta8hDw_EkoouKHcMLLWa2kc/s1600/aDSCN7158.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjBWoOWsezpptYqxOuVjfBUBPB9jNoM3ovdaNztw9aQ12N5qZqmeEYWsr5BDAatO2Crmy0UZY1k2XDXehMuV3WGW7C6XEZsxeap2t6xSeVMK8IAOrISZgceta8hDw_EkoouKHcMLLWa2kc/s200/aDSCN7158.jpg" width="150" /></a></div>
En el <a href="http://balteus.blogspot.com/2011/06/jax-ws-web-services-con-maven.html">artículo anterior</a> explicaba cómo realizar un cliente de Web Service JAX-WS con maven. Las herramientas de JAX-WS generan la url de conexión (endpoint) a partir de la url definida en el WSDL. Sin embargo, desplegar nuestro cliente en un entorno de producción final requerirá que realicemos una programación un poco más afinada y parametrizada permitiendo cambiar la url de conexión (típicamente hacia el servicio de producción final) y establecer timeouts.<br />
<br />
Establecer los timeouts es extremadamente recomendable para prevenir que nuestra aplicación se quede "pegada" al servicio y eventualmente pueda bloquearse toda nuestra aplicación al quedarnos sin threads libres, ya que los tiempos máximos de espera suelen estar indefinidos por defecto.<br />
<br />
Para especificar todo esto no es necesario regenerar el cliente. La práctica habitual es parametrizar los valores de URL, timeout de conexión y timeout de lectura (request timeout) usando algún fichero de configuración o similar, recuperarlos y especificarlos en nuestro proxy cliente.<br />
<br />
A continuación dejo un snippet de código típico de ejemplo:<br />
<br />
<br />
<pre class="brush:java; gutter: false;">import javax.xml.ws.BindingProvider;
import com.sun.xml.ws.client.BindingProviderProperties;
...
int requestTimeout = 5000;
int connectTimeout = 500;
String nuevaUrl = "http://www.cestel.es/jdialer/dataProvider";
Jdialer jdialer = new Jdialer();
BindingProvider bp = (BindingProvider) jdialer.getDataproviderPort();
bp.getRequestContext().put(BindingProviderProperties.REQUEST_TIMEOUT,
requestTimeout);
bp.getRequestContext().put(BindingProviderProperties.CONNECT_TIMEOUT,
connectTimeout);
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
nuevaUrl);</pre>
<br />Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com16tag:blogger.com,1999:blog-1763183641342103044.post-49350632015179792942011-06-19T18:50:00.004+02:002011-07-29T09:09:47.744+02:00JAX-WS Web Services con Maven<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2V-untiLqgvfdAQW6Pp8Peiaw_V_Vq8THwUmpLE-QBv-UnAtRBDv3IUuKBcDa8ZLAgpHQUXoF4f4R-LX9hTYWTF7Qn2Fbc_-35L5eXlHteuazYC6KMCoRF4P1FnJEL1mLedK5PeoDR8g/s1600/http.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="150" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj2V-untiLqgvfdAQW6Pp8Peiaw_V_Vq8THwUmpLE-QBv-UnAtRBDv3IUuKBcDa8ZLAgpHQUXoF4f4R-LX9hTYWTF7Qn2Fbc_-35L5eXlHteuazYC6KMCoRF4P1FnJEL1mLedK5PeoDR8g/s200/http.jpeg" width="200" /></a></div>
Como decía en "<a href="http://balteus.blogspot.com/2010/03/generacion-de-codigo-jaxb-con-maven.html">Generación de código JAXB con Maven</a>", una de las ventajas que aporta maven es la capacidad de automatizar tareas repetitivas y reproducibles del proyecto de desarrollo en el propio gestor del ciclo de vida del mismo independizándolo de la herramienta de desarrollo.<br />
<br />
Por ejemplo, si necesitamos acceder a un Web Service tenemos que generar los artefactos cliente que permitan "consumirlo" (Service Endpoint Interface -SEI-, clases valor de dependencias, etc...) y cada vez que cambie en algo el servicio tendremos que regenerar nuestros artefactos. Si esta tarea se realiza con un IDE, siempre necesitaremos el mismo IDE para actualizarla y (probablemente) pasar por algún tedioso <i>wizard</i>. Con maven, basta tener nuestros fuentes y el fichero pom.xml para que nuestro proyecto se construya en un momento sin instalar ni configurar nada.<br />
<br />
El plugin <span style="font-family: "Courier New",Courier,monospace;">jaxws-maven-plugin</span> provee los adaptadores para las herramientas <span style="font-family: "Courier New",Courier,monospace;">wsgen</span> y <span style="font-family: "Courier New",Courier,monospace;">wsimport</span> de JAXWS a través de los goals jaxws:wsgen y jaxws:wsimport para crear web services y clientes de éstos respectivamente. <br />
<br />
Para crear un web service, bastará con indicar el SEI en la sección execution del plugin y las opciones que queramos (en este caso, generar el fichero WSDL. Por ejemplo:<br />
<pre class="brush:xml; gutter: false;"><plugin>
<groupid>org.codehaus.mojo</groupid>
<artifactid>jaxws-maven-plugin</artifactid>
<version>1.10</version>
<executions>
<execution>
<id>1</id>
<goals>
<goal>wsgen</goal>
</goals>
<configuration>
<sei>cestel.jdialer.provider.DataProviderService</sei>
<genwsdl>true</genwsdl>
</configuration>
</execution>
</executions>
</plugin></pre>
Si queremos crear un cliente para un determinado servicio especificaremos, como habitualmente, el fichero de definición WSDL, el paquete donde queremos que se generen los artefactos y el directorio donde se generarán los ficheros fuente. Por ejemplo:
<br />
<pre class="brush:xml; gutter: false;"><plugin>
<groupid>org.codehaus.mojo</groupid>
<artifactid>jaxws-maven-plugin</artifactid>
<version>1.10</version>
<executions>
<execution>
<id>1</id>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlurls>
<wsdlurl>${project.build.directory}/jaxws/wsgen/wsdl/Jdialer.wsdl</wsdlurl>
</wsdlurls>
<packagename>gesif.sgi.jdialer.dataprovider</packagename>
<sourcedestdir>${basedir}/src/main/java</sourcedestdir>
</configuration>
</execution>
</executions>
</plugin></pre>
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://blogs.oracle.com/enterprisetechtips/entry/using_jax_ws_with_maven">Using JAX-WS with maven</a></li>
<li><a href="http://jax-ws-commons.java.net/jaxws-maven-plugin/">JAX-WS maven plugin</a></li>
<li><a href="http://balteus.blogspot.com/2011/07/cambiar-la-url-de-conexion-y-establecer.html">Cambiar la url de conexión y establecer timeout a un Web Service JAX-WS</a> </li>
</ul>
Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com2tag:blogger.com,1999:blog-1763183641342103044.post-49989211376970107492011-05-19T00:48:00.003+02:002011-05-20T11:44:43.516+02:00Cerrar una sesión de telnet ordenadamente<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDy2hADMfA9pQf52-y3me_1KkBN7vXXszLGMuXjaTCNcDFHjcc8kRYEYjV3sdnyYdkMcno4RsJobNkjK-YlpBLWCIha-zDChZKgbIiVkYH_amAum4nlxEX87IeQMc-rPt-MlsrfZqoHBI/s1600/instant%25C3%25A1nea10.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDy2hADMfA9pQf52-y3me_1KkBN7vXXszLGMuXjaTCNcDFHjcc8kRYEYjV3sdnyYdkMcno4RsJobNkjK-YlpBLWCIha-zDChZKgbIiVkYH_amAum4nlxEX87IeQMc-rPt-MlsrfZqoHBI/s1600/instant%25C3%25A1nea10.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">telnet towel.blinkenlights.nl</td></tr>
</tbody></table>
Antes de que el ssh se extendiera como la forma de inicio de sesión remota a servidores UNIX y Linux, era frecuente realizar sesiones de telnet para acceso a una consola del servidor. Actualmente, el uso del telnet se limita prácticamente a realizar sesiones 5250 o 3270 hacia AS/400 o Mainframes o se reduce a realizar meras pruebas de conectividad TCP básicas cuando no tenemos el <a href="http://www.hping.org/">hping</a> a mano y un tcptraceroute nos resulta teclear demasiado.<br />
<br />
Siempre que realizamos un telnet solemos ver un mensaje "<span style="background-color: white; color: black; font-family: "Courier New",Courier,monospace; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">Escape character is '^]'.</span>" como el siguiente:<br />
<br />
<div style="font-family: "Courier New",Courier,monospace;">
<span id="internal-source-marker_0.6677783540181208" style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">zarza@szarza:~$ telnet ftp.es.debian.org 80</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">Trying 82.194.78.250...</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">Connected to ftp.es.debian.org.</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">Escape character is '^]'.</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;"></span><span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">^]</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">telnet> quit</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">Connection closed.</span><br />
<span style="background-color: white; color: black; font-size: 10pt; font-style: normal; font-weight: normal; text-decoration: none; vertical-align: baseline;">szarza@szarza:~$</span></div>
<br />
Hasta ahora, nunca había sabido cancelar las conexiones de telnet que se quedaban pegadas, así que acababa matando la sesión cerrando el proceso padre del telnet (konsole, xterm, cmd.exe, etc) porque no me había preocupado de saber cómo obtener y enviar la famosa secuencia "^]". Sin embargo, es bastante sencillo: <b>se trata de la combinación CTRL+ALT GR+]</b>, lo cual es lógico: "^" significa CTRL y el carácter ] se obtiene pulsando la tecla "Alt Gr"+]. Una vez en el prompt del telnet, podemos poner "quit" para salir.<br />
<br />
Por otro lado, este artículo me ha servido para comprobar que <a href="http://www.blinkenlights.nl/services.html">sigue estando disponible</a> la película Star Wars Episode IV en ASCII vía telnet haciendo "<span style="font-family: "Courier New",Courier,monospace;">telnet towel.blinkenlights.nl</span>" gracias a <a href="http://www.asciimation.co.nz/">Simon Jansen</a>.Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com4tag:blogger.com,1999:blog-1763183641342103044.post-75524763751749163122011-05-07T21:04:00.005+02:002011-05-07T23:27:58.044+02:00Solar System Scope: el sistema solar a tu alcance<blockquote>
<div style="text-align: right;">
<small><span style="font-family: tahoma;"><big><i>Lo maravilloso de aprender algo, es que nadie puede arrebatárnoslo.</i><br />
</big></span></small></div>
<div align="right">
<span style="font-family: tahoma; font-size: x-small;">-- B. B, King.</span></div>
</blockquote>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD_U4OYRQui9sSKcNvOBBhzEsotw7T9Qa_cYlIUsKkTqRjP8UOlKDx2gycnBg6nPqc_cJQ19J7peLZAnGU-l69RomTgnv0T5O3z0GbXofOz67tLop8vRZj0r5z2n-KlJEw44KNGYB0sTc/s1600/instant%25C3%25A1nea8.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjD_U4OYRQui9sSKcNvOBBhzEsotw7T9Qa_cYlIUsKkTqRjP8UOlKDx2gycnBg6nPqc_cJQ19J7peLZAnGU-l69RomTgnv0T5O3z0GbXofOz67tLop8vRZj0r5z2n-KlJEw44KNGYB0sTc/s640/instant%25C3%25A1nea8.png" width="640" /></a></div>
<br />
Hace casi dos años, escribí un <a href="http://balteus.blogspot.com/2009/06/sideralis-un-stellarium-en-tu-movil.html">artículo</a> sobre Sideralis, un planetario para móviles gratuito muy práctico. Desde entonces hasta ahora los móviles han cambiado mucho y han aparecido productos software espectaculares para astronomía en todas las plataformas. Por ejemplo, he tenido la ocasión de ver <a href="http://www.gosoftworks.com/GoSoftWorks/Home.html">GoSkyWatch</a> funcionando en un iPhone 4 y es realmente impresionante.<br />
<br />
Pero lo que hoy traigo aquí es igualmente impresionante, y no hace falta ni tener un iPhone ni siquiera instalarse nada, tan sólo un navegador y curiosidad.<br />
<a href="http://www.solarsystemscope.com/">Solar System Scope</a> es un simulador interactivo 3D del sistema solar online realmente espectacular. A diferencia de otros simuladores 2D estáticos (<a href="http://space.jpl.nasa.gov/">como el de la NASA</a>) o dinámicos (<a href="http://gunn.co.nz/astrotour/">como el de Gunn Interactive</a>), éste permite movernos a través del sistema solar con total libertad de navegación e incluso de representación, ya que nos permite cambiar la escala del sistema (tanto en distancia como en tamaño de los objetos).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc7s5XyTBVGOaLUE8di6Pyh0hD9HBvDFhNAPdUPrmMqlYCC9VFnDqNM82c-yTOBOv5iTXxIIOnGyQyGXrFjTe3y4tDxSSwLUqej4s22dIGbeM1Xc3SSbaeach2aF22rgCs2zNQLqn47CQ/s1600/instant%25C3%25A1nea9.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="512" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhc7s5XyTBVGOaLUE8di6Pyh0hD9HBvDFhNAPdUPrmMqlYCC9VFnDqNM82c-yTOBOv5iTXxIIOnGyQyGXrFjTe3y4tDxSSwLUqej4s22dIGbeM1Xc3SSbaeach2aF22rgCs2zNQLqn47CQ/s640/instant%25C3%25A1nea9.png" width="640" /></a></div>
<br />
No sólo es un buen simulador del sistema solar: <b>es el mejor que he visto</b>. Sus posibilidades de interacción lo hacen tan entretenido, que te puedes pasar un buen rato jugando con múltiples ángulos de observación (desde cada planeta haciendo doble clic) y observando las posiciones y movimientos a través de una representación desproporcionada para
que nos quepan todos los planetas en pantalla.<br />
<br />
Como elemento didáctico para los niños, es verdaderamente genial, porque se puede jugar con la escala para enseñarles (al poner el sistema en escala real) las enormes distancias del sistema, cómo Urano gira tumbado con sus anillos prácticamente en vertical con respecto al plano orbital, mostrar las fases de la luna y por qué vemos siempre su misma cara, que no sólo Saturno tiene anillos o el extraño amanecer de Venus por el Oeste.<br />
<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://2.gvt0.com/vi/_943XB4gcN4/0.jpg" height="266" width="320"><param name="movie" value="http://www.youtube.com/v/_943XB4gcN4&fs=1&source=uds" />
<param name="bgcolor" value="#FFFFFF" />
<embed width="320" height="266" src="http://www.youtube.com/v/_943XB4gcN4&fs=1&source=uds" type="application/x-shockwave-flash"></embed></object></div>
<br />
Aunque aún le faltan funcionalidades por terminar (como la localización de estrellas o planetas), puedes comprobar que tiene una interfaz muy sencilla que te hará pasar un rato ameno y entretenido aprendiendo o visualizando aquello que aprendimos hace años. Prúebalo y me cuentas.<br />
<br />
<br />
<span style="color: #990000;"><b>Referencias y más información:</b></span><br />
<ul>
<li><a href="http://www.solarsystemscope.com/">Solar System Scope</a> </li>
<li><a href="http://gunn.co.nz/astrotour/">Simulador de Gunn Interactive</a></li>
<li><a href="http://space.jpl.nasa.gov/">Simulador de la NASA</a></li>
</ul>Samuel Zarzahttp://www.blogger.com/profile/10909786707589321531noreply@blogger.com0