Páginas

jueves, 23 de diciembre de 2010

La programación y el mundo de la noche

El otro día anda ojeando algunos blog sobre programación a través de Google Reader cuando me paré a leer una artículo sobre Tapestry. Una parte importante del proyecto en el que me encuentro trabajando ahora se está desarrollando con éste framework así que me paré a leer el post. Desgraciadamente sólo puedo leer y no opinar porque aunque estamos trabajando con Tapestry yo personalmente no he tenido la oportunidad de tocarlo.

El autor del post, Igor Drobiazko, criticaba la mala posición que Tapestry había optenido en una comparación de JVM Web Frameworks reciente por Matt Raibley y argumentaba cómo éste framework merecía mejor puntuación en diversos aspectos.

Cuál fue mi sorpresa cuando reconocí al primer comentarista del post. ¡Ay va! ¡Si yo he trabajado con este tío! Más sorpresa me llevé al leer el comentario donde empezaba diciendo que también se tendría que haber tenido en cuenta a ATG en la comparación. ¿A qué viene este comentario sobre ATG que nada tiene que ver con el post y qué hace este tío hablando de ATG? OK, el proyecto donde estoy y en el que coincidí con este individuo está basado principalmente en ATG pero él nunca llegó a trabajar con ATG. La respuesta creo que es simple: escribes un post y cometas algo sobre ATG y de esa forma tu nombre queda vinculado a este producto.

Esta persona de la que hablo no duró más de mes y medio en el proyecto ya que hubo que echarlo porque su productividad era prácticamente cero. Sin embargo, cuando llegó prometía mucho ya que se le llenaba la boca de tecnologías y presumía de conocer a mucha gente en esto del Java. Que si yo conozco al creador de tal framework, que si el creador de este otro es amigo mío... Eso sí, lo que es trabajar, cero. Cada vez que pasaba por delante de su monitor estaba conectado a LinkedIn o Twitter.

Me pongo a investigar al pájaro este y resulta que en su perfil de LinkedIn dice que todavía sigue trabajando en nuestro proyecto (dos meses y medio hace ya que lo echamos) como experto en seguridad y el que viene a decir que "nos ayuda" (algo así como asesora) cuando su perfil era el de programador raso. Entre miles de referencias en Google y el que el perla se ve que no escatima en tiempo a la hora de comentar blogs se puede leer como dice que tiene 18 años de experiencia (¿?¿?), conocimientos y experiencia en un sin fin de tecnologías, su propia fundación y miles de tontearías. Eso sí, su más de 500 conexiones en LinkedIn (otro que se piensa que LinkedIn es un Facebook) y otras tantas en Twitter.

Menudo personaje. Teniendo en cuenta lo que duró en nuestro proyecto, el rol que realizó y lo que él va describiendo por ahí que hizo (o está haciendo) me puedo imaginar cómo prácticamente nada de lo que se puede leer en su perfil de LinkedIn es cierto. Por cierto, echo de menos un botón "esto es mentira" en esta "red social".

A mí este personaje me recuerda a la gente del mundo del corazón. A esas personas que desean la fama y que no pudiéndola conseguir por sí solos se dedican a ir de sarao en sarao buscando a personajes famosos para relacionarse con ellos y conseguir fotos, relaciones, amistades y un sin fin de cosas. Con el tiempo algunos de estos personajes pueden ser confundidos con famosos.

En fin, cuidado con este tipo de personajes.

lunes, 15 de febrero de 2010

Leyes epónimas relacionadas con el desarrollo de software

En Variable Not Found han recogido 30 leyes epónimas relacionadas con el Software. He echado unas risas al leerlas aunque la risa no dura mucho al darme cuenta de que he sufrido ésta o aquella ley. Hay una que especialmente me ha hecho gracia:

8. Ley de Brooks

Incluir trabajadores en un proyecto retrasado hará que éste avance aún más lentamente.
Esta gran ley me recuerda una conversación telefónica que tuve hace unos meses:
Gerente: Voy a sacar a fulanito de proyecto porque hace falta para otro con urgencia.
Juande: ¡Pero si entró hace tres semanas y me ha costado dos y medias formarlo! ¡Y vamos con retraso!
G.: No te preocupes, te meto a otra persona.
J.: Eso retrasará más el proyecto.
G.: Pues metemos a dos.

miércoles, 16 de diciembre de 2009

Spring + Quartz + Clustering

En Javi's Java podemos encontrar un estupendo post a cerca de Quartz, sobre qué es y cómo se configura dentro de nuestra aplicación Web por lo que no es necesario hablar mucho más del tema. En este post sólo me gustaría resaltar la sencillez y elegancia resultante de la integración de Quartz con Spring, como el mismo Javi comentaba en uno de los comentarios, que nos permite configurar una tarea en apenas un par de minutos.

Tampoco es necesario escribir ninguna línea de código como ejemplo para la integración con Spring ya que la documentación de Spring sobre el tema (cronExpression) es clara y sencilla.

¿Quién necesita ahora los crones de Linux o las tareas de Windows para programar tareas relacionas con nuestra aplicación Web?

Si además necesitamos ejecutar la aplicación en distintas instancias y no queremos que haya problemas, como que el proceso se ejecute simultáneamente en todas ellas, podemos configurar Quartz para que se ejecute en Clustering añadiendo sólo unas cuántas líneas extras en la configuración. Ejemplo de configuración en Spring para la ejecución de Quartz en clustering:

<bean name="job" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="whatabout.Job" /> <property name="jobDataAsMap"> <map> <!-- properties <entry key="timeout" value="" /> --> </map> </property> </bean> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job" /> <property name="cronExpression" value="0 0 6 * * ?" /> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> <property name="applicationContextSchedulerContextKey"> <value>applicationContext</value> </property> <property name="startupDelay" value="0" /> <property name="waitForJobsToCompleteOnShutdown" value="true" /> <property name="dataSource" ref="myDataSource" /> <property name="quartzProperties"> <props> <!-- ThreadPool --> <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop> <prop key="org.quartz.threadPool.threadCount">5</prop> <prop key="org.quartz.threadPool.threadPriority">5</prop> <!-- Job store --> <prop key="org.quartz.jobStore.misfireThreshold">60000</prop> <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop> <prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.StdJDBCDelegate</prop> <prop key="org.quartz.jobStore.useProperties">false</prop> <!-- Clustering --> <prop key="org.quartz.jobStore.isClustered">true</prop> <prop key="org.quartz.scheduler.instanceId">AUTO</prop> <prop key="org.quartz.jobStore.clusterCheckinInterval">30000</prop> </props> </property> </bean>

jueves, 9 de abril de 2009

Google App Engine and Struts

Recientemente hemos podido leer como ahora Google App Engine soporta Java. Ni corto ni perezoso me he lanzado a probarlo. Pero ya puestos no nos íbamos a conformar con probar un simple Servlet ¿no?

En este enlace podemos ver una prueba de Google App Engine funcionando con Struts 1.3.

Para desarrollar la aplicación y desplegarla he utilizado el plugin de Google para Eclipse.

Por ahora me he quedado aquí, pero habrá que seguir estudiando todas las posibilidades que Google App Engine nos ofrece a los desarrolladores Java.

viernes, 13 de febrero de 2009

Maven corrompe las imágenes

"Maven está corrompiendo las imágenes" es una frase que que he oido a tres compañeros de mi proyecto actual. Tranquilos, no os preocupeis por eso - les dije yo.

¿Por qué Maven corrompe las imágenes cuando por ejemplo, construimos un war con nuestra aplicación Web? Este problema surge cuando "filtramos" nuestros archivos de recursos (src/main/resources) para sustituir las variables indicadas con los delimitadores ${...}. Qué gran utilidad sin duda para poder construir nuestra aplicación Web para diferentes entornos de forma simple y automática.

¡¡Pero es que corrompe las imáganes!! La solución es bastante sencilla, sólo debéis buscar en Google las siguientes palabras: maven filtering resource images y en la segunda entrada, además de explicaros qué es eso del filtrado, os da la solución para que éste no corrampa las imágenes u otros archivos.

Aquí os pongo el fagmento en particular:

<project> ... <build> ... <resources> <resource> <directory>src/main/resources</directory> <filtering>true</filtering> <excludes> <exclude>**/*.jpg</exclude> </excludes> </resource> <resource> <directory>src/main/resources</directory> <filtering>false</filtering> <includes> <include>**/*.jpg</include> </includes> </resource> ... </resources> ... </build> ...</project>


Aquí os dejo el enlace con más detalles: http://maven.apache.org/plugins/maven-resources-plugin/examples/filter.html

lunes, 29 de diciembre de 2008

Supervivencia a la hora de escribir código

"Always code as if the person who will maintain your code is a maniac serial killer that knows where you live"

Y es que, nunca se sabe si la persona que va a mantener tu código es un programador o un asesino en serie. Pero claro, qué fue antes, ¿el huevo o la gallina?, porque ¿a quienes no os ha entrado ganas de matar a alguien tras ver algunas líneas de código? A mí sí, es algo que ya sabéis.

Por otro lado, si queréis mantener vuestro puesto de trabajo para siempre, corriendo el riesgo de ser asesinado por un asesino en serie claro está, siempre podéis usar las técnicas de escritura de código inmantenible. Si echáis un vistazo a estas prácticas seguro que os daréis cuenta que sois habituales en algunas de ella aunque de forma menos exagerada (o quizás no). Tal vez sea nuestro instinto de supervivencia lo que nos hace escribir código inmantenible pero paradójicamente esto nos pueda llevar a ser asesinados  por un asesino en serie.

viernes, 5 de diciembre de 2008

Spring - JPA - Hibernate

Estos días he tenido que montar el esqueleto para un nuevo proyecto. Para mi sorpresa la combinación de Frameworks que se requerían no estaba entre las disponibles de Appfuse Light así que tuve que montarla casi desde cero.

Son muchos los ejemplos y la documentación que se puede encontrar que hablan acerca de cómo montar JPA con Spring, pero como suele suceder casi todos proceden de un ejemplo original por lo que al final todos quedan reducidos a muy pocos que para colmo, están incompletos. Así pues, voy a hacer mi pequeña aportación y describiré el archivo de Spring al completo. No describiré cómo se realizan Test o cómo se crean claves primarias compuestas porque son temas que ya tratan bien en otros blogs.

En primer lugar, empezaré definiendo una entidad, sobre la que girará el ejemplo: User.

package es.whatabout.model; @Entity @Table(name = "USER") public class User{ @Id @Column(name = "ID") private Integer idUser; @Column(name = "FIRST_NAME") private String firstName; @Column(name = "LAST_NAME") private String lastName; ...get/set methods...


Como se puede ver, esta clase lleva anotaciones JPA que identifican a esta clase como un entidad, su clave primaria y el mapeo de sus atributos a la tabla y columnas correspondientes en la base de datos. Esta será la única clase que contenga anotaciones ya que el resto de la configuración, como la transaccionalidad, la configuraremos desde Spring.

Antes de definir la clase DAO crearemos un interfaz genérico y su implementación que proporcionará a nuestro dao particular y a todos los que generemos (y su implementaciones) de todos los métodos CRUD gracias a los tipos genéricos de Java.

import java.io.Serializable; import java.util.List; public abstract interface GenericDao <T, PK extends Serializable> { public abstract List<T> getAll(); public abstract T findByPK(PK id); public abstract void update(T object); public abstract void remove(T object); public abstract void insert(T object); }

Y su implementación.

package es.whatabout.dao.impl; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.orm.jpa.support.JpaDaoSupport; import es.whatabout.dao.GenericDao; public class GenericDaoImpl extends JpaDaoSupport implements GenericDao { private static Log logger = LogFactory.getFactory().getInstance(GenericDaoImpl.class); private Class persistentClass; public GenericDaoImpl() { this.persistentClass = (Class) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; } public void insert(T t) { getJpaTemplate().persist(t); } public T findByPK(PK id) { return getJpaTemplate().find(persistentClass, id); } public List getAll() { List entities = new ArrayList(); try { String s = "select c from " + persistentClass.getSimpleName() + " c"; entities = getJpaTemplate().find(s); } catch (Exception e) { logger.error(e.getStackTrace()); } return entities; } public void remove(T t) { getJpaTemplate().remove(getJpaTemplate().merge(t)); } public void update(T object) { getJpaTemplate().merge(object); } }


T será la entidad que maneje nuestra clase dao mientras que PK será la clase de la clave primaria de ésta, que puede ser de tipo simple o compuesta (composed primary key)

A continuación crearemos una interfaz para un dao particular y su implementación utilizando el interfaz y la implementación de éste antes definido.

package es.whatabout.dao; import es.whatabout.model.User; public interface UserDao extends GenericDao<User, Integer> { }

Vemos que nuestro interfáz es muy simple, ya que dispone de los métodos CRUD del interfaz GenericDao. Del mismo modo, su implementación también será muy simple ya que ésta extiende de la implementación de GenericDao, GenericDaoImpl

package es.whatabout.dao.impl; import es.whatabout.dao.UserDao; import es.whatabout.model.User; public class UserDaoImpl extends GenericDaoImpl<User, Integer> implements UserDao{ }

Sólo queda definir el archivo de configuración de Spring:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http:// www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- archivo de configuracion para los datos de conexion --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:jdbc.properties" /> </bean> <!-- Transaccionalidad para todas las clases del paquete indicado --> <aop:config> <aop:advisor id="managerTx" advice-ref="txAdvice" pointcut="execution(* es.whatabout.dao.impl.*.*(..))" /> </aop:config> <!-- restringimos a solo lectura las transacciones metodos que comienzan por get --> <tx:advice id="txAdvice"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="*" /> </tx:attributes> </tx:advice> <!-- configuramos el transaction manager--> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="dataSource" ref="dataSource" /> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> <!-- Conexion a bd con las propiedades del arhivo jdbc.properties--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}" /> <property name="url" value="${jdbc.url}" /> <property name="username" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- configuramos la Factory Manager, que trabajará con hibernate--> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="showSql" value="true" /> <property name="databasePlatform" value="${hibernate.dialect}" /> </bean> </property> <property name="jpaProperties"> <value>hibernate.show_sql=true</value> </property> </bean> <!-- configuramos LOG4J --> <bean id="log4jInitialization" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="targetClass" value="org.springframework.util.Log4jConfigurer" /> <property name="targetMethod" value="initLogging" /> <property name="arguments"> <list> <value>classpath:log4j.xml</value> </list> </property> </bean> <!-- inyeccion del entityManagerFActory a nuestro Dao particular--> <bean id="userDao" class="es.whatabout.dao.impl.UserDaoImpl"> <property name="entityManagerFactory" ref="entityManagerFactory" /> </bean> </beans>


Con este archivo de configuración ya podemos disponer de nuestro dao capaz de realizar todas las operaciones CRUD sin ningún problema.

Referencia: The Spring Framework - Reference Documentation, chapter 9, Introduction to Spring 2 and JPA
Código: descargar