Páginas

domingo, 20 de mayo de 2012

Migración desde Jetty 6 a Jetty 8

Siempre suelo trabajar con Jetty como servidor local utilizando el plugin que éste proporciona para Maven. A pesar de que me gusta trabajar con las últimas versiones de las librerías con las que trabajo, hace poco me di cuenta de que no estaba trabajando con la última versión de Jetty, la 8. El error era debido a que desde su versión 7 Jetty pasó a formar parte de la fundación Eclipse y esto hizo que cambiaran de paquetes y que el plugin para Maven cambiara de nombre. Mientras que la versión 6 de Jetty y anteriores se encuentra bajo en artifact maven-jetty-plugin, la 7 y posteriores se encuentran bajo jetty-maven-plugin. Así, la configuración del Plugin de Maven para la nueva versión quedaría así:

<plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.3.v20120416</version> <configuration> <webAppConfig> <contextPath>/</contextPath> </webAppConfig> </configuration> </plugin>
Esta sería su configuración más sencilla, sin embargo, si estamos utilizando configuración más compleja directamente sobre el plugin o a través del archivo jetty.xml también debemos tener en cuenta la repaquetización que he comentado antes.

Digamos que queremos configurar un recurso JNDI como podría ser la conexión a la base de datos. Antes, esto se hacía sobre la configuración del servidor y la clase org.mortbay.jetty.Server en el archivo jetty.xml mientras que ahora el uso del archivo jetty.xml queda para la configuración del servidor y el archivo jetty-env.xml para la configuración de nuestra aplicación Web. Así, teniendo el cuenta los nuevos paquetes, la configuración del recurso JNDI en el fichero jetty-env.xml quedaría así:
<Configure class="org.eclipse.jetty.webapp.WebAppContext"> <New id="epago" class="org.eclipse.jetty.plus.jndi.Resource"> <Arg>jdbc/epago</Arg> <Arg> <New class="org.apache.commons.dbcp.BasicDataSource"> <Set name="driverClassName">oracle.jdbc.OracleDriver</Set> <Set name="url">jdbc:oracle:thin:@172.111.111.111:1521:XE</Set> <Set name="username">user</Set> <Set name="password">pass</Set> </New> </Arg> </New> </Configure>
¿Y si queremos hacer algún cambio en la confiugraicón del servidor, como podría ser el puerto de arranque? Como hemos dicho, esta configuración sí sería propia del archivo jetty.xml y seria algo así:
<Configure class="org.eclipse.jetty.server.Server"> <Call name="addConnector"> <Arg> <New class="org.eclipse.jetty.server.nio.SelectChannelConnector"> <Set name="port">8081</Set> <Set name="maxIdleTime">3000</Set> </New> </Arg> </Call> </Configure>
Finalmente, veamos cómo quedaría la configuración del plugin:
<plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>8.1.3.v20120416</version> <dependencies> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.2.0</version> </dependency> </dependencies> <configuration> <webAppConfig> <contextPath>/myApp</contextPath> </webAppConfig> <systemProperties> <systemProperty> <name>javax.net.ssl.trustStore</name> <value>d:/Keystore</value> </systemProperty> </systemProperties> <jettyEnvXml>target/${project.build.finalName}/WEB-INF/jetty-env.xml</jettyEnvXml> <jettyXml>target/${project.build.finalName}/WEB-INF/jetty.xml</jettyXml> </configuration> </plugin>
En la última configuración se puede ver cómo se hacen referencia a los archivos jetty.xml y jetty-env.xml antes nombrados, cómo se añaden librerías necesarioas para el recurso JNDI definido y cómo, finalmente, se configura para que trabaje con un almecén de claves seguro y así poder acceder a recursos seguros como podría ser un servicio Web bajo HTTPS.

Algunos enlaces de interes:

jueves, 16 de febrero de 2012

Primate programming

Hace unos días leía en Mundo geek una cita de James Goldsmith que decía:
Si pagas cacahuetes, obtienes monos
Generalmente cierto. También es verdad que muchos conocen perfectamente esa relación y qué obtendrán con cacahuetes sin embargo, piensan que un grupo de monos puede llevar a cabo cualquier tarea. A esas personas, les dejo este enlace donde pueden encontrar primates con gran experiencia a unas tasas muy reducidas.

Depurar mensajes SOAP con Spring WS

Son muchos los que preguntan por la red cómo depurar (logar, tracer, ...) los mensajes SOAP cuando se utiliza Spring WS. Yo también me lo he preguntado así que aquí va la solución.

Lo primero que hay que saber es que no es lo mismo depurar los mensajes SOAP cuando estamos en el lado del cliente, es decir, estamos implementando una llamada a un servicio Web o en el lado del servidor, esto es, estamos implementando el servicio Web. La forma de depurar los mensajes SOAP es distinta para cada caso.

En el lado del servidor tenemos dos alternativas:
  • Utilizar interceptores. Concretamente debemos utilizar PayloadLoggingInterceptor SoapEnvelopeLoggingInterceptor. Podéis encontrar información más detallada en la documentación de Spring, justo aquí. Cuando os decidais por uno de los interceptores, no hay que olvidad activar el nivel de DEBUG para el paquete al que pertenece.
  • Activar el nivel DEBUG o TRACE para el paquete org.springframework.ws.server.MessageTracing. Más información aquí.
En el lado del cliente:
  • Activar el nivel de DEBUG o TRACE para unos paquetes particulares:
    • org.springframework.ws.client.MessageTracing.sent para los mensajes salientes
    • org.springframework.ws.client.MessageTracing.received para mensajes entrantes.

martes, 14 de febrero de 2012

Servicios Web y XML

Recientemente he estado trabajando con Servicio Web con Spring WS y me he encontrado algunos problemas de librerías relacionadas con Servicios Web y XML, especialmente al desplegar estos servicios en servidores de aplicaciones como Welogic o JBoss. Tras algunas tortas me ha quedado medianamente claro para qué sirven algunas de las librerías. En este post trato de aclarar algo para qué sirven todas estas librerías.

  • SAAJ (SOAP with Attachments API for Java). Proporciona una forma estándar de enviar documentos XML a través de Internet desde Java. Dicho de otra forma, SAAJ permite a producir y consumir mensajes acorde con la especificación SOAP 1.1 y SOAP con adjuntos. Otros datos:
    • Opera a un nivel inferior que JAX-RPC y JAX-WS que usan SAAJ.
    • Forma parte del JDK. Particularmente, la versión Java 6 incluye SAAJ 1.3
    • Para aplicaciones Web, la implementación es típicamente provista por el servidor de aplicaciones.
  • JAXP (Java Api for XML Processing). API Java (definido por Sun Microsystems) sirve para la manipulación y el tratamiento de archivos XML. Otros datos:
    • Es parte del JDK. En  la versión Java 6 podemos encontrar JAXP 1.4 mientras que en Java 5 encontramos la versión 1.3 que está obsoleta.
    • El JDK también proporciona una implementación (Xerces a partir de JDK5 y anteriormente Crimson).
  • JAXB (Java Architecture for XML Binding). Permite a los desarrolladores Java mapear clases Java a representaciones XML. JAXB proporciona dos características principales: la habilidad de convertir (marshal) objetos Java en XML y viceversa. En otras palabras, permite almacenar y extraer datos en memoria en cualquier formato XML sin la necesidad de tener que implementar código específico. Otros datos:
    • Es parte de JDK. Particularmente, la versión Java 6 (updated 4) viene con  JAXB 2.1
    • La implementación de referencia es parte del proyecto Glassfish
    • Aquí encontrarás una descripción más completa sobre JAXB
  • JAX-RPC (Java API XML para RPC) es una especificación para desarrolladores Java para el desarrollo de Web servicios basados en SOAP. Este API está obsoleto en favor de JAX-WS. Otros datos:
    • Tiene su propio modelo de mapeo de datos (data mapping model) que cubre el 90% de los esquemas. Los esquemas que no son cubiertos son mapeados  javax.xml.soap.SOAPElement.
    • El modelo controlador (handler model) está basado en SAAJ 1.2
    • Era el API de Servicios Web en el JDK1.4
  • Apache Xerces. Es una librería de Apache para el parseo, validación, serialización y manipulación de XML. Actualmente se encuentra en su versión 2 y aunque se puede encontrar como una librería independiente también forma parte del JDK. Otros datos:
    • Ofrece una implementación del API JAXP 1.4 entre otros APIs
    • Fue re-paquetizado bajo el paquete com.sun en el JDK5
    • La implementación es típicamente provista por el servidor de aplicaciones como se describe aquí.
  • Apache Xalan. Es un procesador XSLT para la transformación de documentos XML en documentos HTML, textos, u toros tipos de documentos XML. Otros datos:
    • Al igual que Xerces, forma parte del JDK y a partir de la versión 5 fue re-paquetizado bajo sun.com.
    • Implemente XPath entre otros.
    • La versión 1 ya no está soportada por lo que es recomendable trabajar con la versión 2.
  • JAX-WS (Java Api for XML Web Services) es el API Java que se utiliza para la creación de Web Service. JAX-WS forma parte del estándar Java EE. La implementación de referencia de JAX-WS es parte del proyecto GlassFish. En la plataforma Java EE 5, JAX-WS 2.0 reemplaza al API JAX-RPC (obsoleto). El cambio se basa en moverse hacia Web Services orientados a documentos (en vez de RPC). Otros datos:
    • Como modelo de mapeo de datos utiliza JAXB
    • El controlador de modelo (model handler) se base en SAAJ 1.3
    • Pasó a formar parte del JDK5 en su versión 2.0. La versión  JAX-WS 2.1 fue introducida en Java 6 Update 4.
    • JAX-WS 2.1 fue incluido en Java 6, particularmente en JDK 1.6.0_04 y superior.
    • JAX-RPC vs JAX-WS
Por último, dejo algunos enlaces interesantes:

martes, 31 de enero de 2012

Homogeniedad

Es un hecho el que a la hora de programar alguna aplicación nos tropecemos con muchos problemas. Muchos de estos serán repetidos, es decir, mismo problema en distinto punto de la aplicación.

¿Qué sucede cuando uno se encuentra por segunda vez con un problema que ya ha resuelto en otro punto de la aplicación/código?
  • Podemos acudir a nuestra primera solución y a ser posible no duplicar el código para que tengamos en un mismo punto la solución a distintos problemas del mismo tipo.
  • Podemos dar de nuevo solución al problema ignorando la primera solución porque, por ejemplo, se nos ha ocurrido una mejor implementación.

Suele pasar que cuando nos enfrentamos una segunda o tercera vez con el mismo problema se nos ocurra una mejor forma de implementar la solución. En este caso creo que es un error implementar una nueva solución aunque esta sea mejor que la anterior. De lo que se trata es de evitar tener dos problemas del mismo tipo con dos soluciones distintas. Si decides implementar una segunda solución tienes que modificar el código ya escrito para que todos los problemas de dicho tipo tengan la misma nueva solución (fácil si se ha centralizado es punto del código). Si este paso es muy costoso, homogeneizar la solución, olvídalo y sigue con la implementación actual por que lo que sí será costoso en un futuro será mantener un código donde cada cual y según el momento decidió implementar una solución distinta para el mismo problema.

Por otro lado, y aunque parezca raro, también se da el caso de tener varios problemas implementados con la misma solución. ¿Como se llega a esta punto? Fácil. Tras encontrarse con el segundo problema, distinto al primero se decide que aunque distinto es parecido así que se decide introducir unas pequeñas modificaciones (normalmente introduciendo cláusulas if y más parámetros en la llada) en la primera solución. Esto suele sucede en los programadores empeñados en "generalizar" código y puede acabar en un método con infinitas líneas y llenos de if. No es de extrañar luego que hagas algunas modificaciones para que el código también resuelva un nuevo problema y que la hacerlo dejen de funcionar otros dos.

Por eso, que digo yo, y esto es sólo una opinión, señores:
  • Mismo problema: misma solución
  • Distintos problemas: distintas soluciones.

miércoles, 3 de agosto de 2011

Variables globales

El otro día leía en Mundo Geek cómo las variables globales son malvadas. En el post enumeraba las razones por las que las variables globales, lejos de ser nuestras amigas, son malvadas:
  1. El código es más difícil de entender
  2. El código es más difícil de depurar
  3. El código es más difícil de testear
  4. El código es más difícil de mantener
  5. El código es más difícil de reutilizar
  6. Las variables globales matan gatitos
Yo añadiría, desde luego, una más y es que en manos inexpertas y/o malvadas pueden llegar a ser unas de las cosas más peligrosas en el mundillo de las aplicaciones

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.