Páginas

domingo, 9 de junio de 2013

Apache CXF - Contract First

Estos días tuve que montar un servicio Web utilizando Apache CXF y la estrategia de Contrato Primero (partimos del WSDL para generar el código Java). Es algo sencillo de montar, sin embargo, me tomó mucho más de lo previsto guiado por ejemplos erróneos y una documentación más que escasa.

Por un lado, la documentación oficial es escasa, como ya he comentado, pero e incluso los ejemplos oficiales son confusos ya que tienen archivos de contexto innecesarios y no se ejecutan tan fácilmente como deberían.

Por otro lado, muchos de los ejemplos que podemos encontrar en Internet no comentan algunos puntos básicos, están equivocados en algunos puntos y para rematar no funcionan.

Así que voy a aportar yo un ejemplo sencillo y ejecutable sin ningún problema. Lo podéis descargar en esta ruta. El ejemplo se puede ejecutar fácilmente con Maven y gracias al plugin de Jetty.

Algunos comentarios:

  • Para generar los artefactos Java, se utiliza el plugin cxf-codegen-plugin que no sólo genera los artefactos Java sino que también genera el interfaz del servicio. Este último punto es muy importante y el algo que olvidan citar casi todos, sino todos los ejemplos que he visto.
  • Al disponer del Interfaz del servicio, sólo necesitamos implementar el servicio y no crear el Interfaz por nuestra cuenta (como intentan muchos ejemplos). Primero, porque es una tarea inneceesaria. Segundo, por que posiblemente entre en conflicto con el interfaz ya generado por el plugin.
  • En la definición del EndPoint, dentro del contexto de Spring, no es necesario añadir el atributo wsdlLocation como parte del enfoque "contrato primero" sin embargo, sí es necesario si queremos que no se genere el WSDL cada vez que demandemos éste o si queremos validar las peticiones sobre el esquema.

sábado, 8 de junio de 2013

La responsabilidad del cliente

Estos días volví a ver una de esas imágenes que recorren Internet y que llegan a tus manos una y otra vez. Hablo de esta imagen:

Está claro que te echas unas risas. En esta ocasión, me paré un poco más a mirar la imagen y vi cómo ésta se cebaba con el proveedor y cómo el cliente queda simplemente como alguien que no supo explicar perfectamente lo que quería. ¿Es esta la realidad? Yo diría que no. No quita que lo que vemos, aunque exagerado, sea lo que los que nos dedicamos a esto de la consultoría vemos casi a diario, pero no se muestra toda la verdad.

Podríamos resumir la viñeta simplemente diciendo que los proveedores no son serios y que esta falta de seriedad es la causante de muchos problemas. ¿Pero por qué no es serio un proveedor? Simplemente, por que el cliente no es serio. Y un cliente puede no ser serio por muchas cosas, pero principalmente por dos motivos: presupuesto y plazos.

¿Qué sucede cuando el proveedor adjudica la oferta al proyecto más barato y con los plazos de entrega más cortos? Todos sabemos lo que sucede.

Cuando un cliente presenta una oferta con un presupuesto que no da ni para la mitad de lo que quiere, con unos plazos imposibles y con unos requisitos que no llegan a media docena y que apenas reflejan una remota idea de lo que quieren, no puede esperar que se presenten a la oferta proveedores serios.

Dicho esto, extiendo las viñetas con más información sobre cliente:

Los proveedores empezarán a ser serios cuando el cliente empieza a serlo.

martes, 28 de agosto de 2012

Tracear tiempos de ejecución con AOP

En ocasiones las aplicaciones que desarrollamos deben realizar pruebas de rendimiento para determinar cómo responden y detectar los posibles errores que podemos llegar a tener en un entorno estresado. Muy común entre estas pruebas de rendimiento es que se nos pida el estudio de los tiempos de acceso a base de datos y el tiempo que nuestros métodos requieren para devolver los datos que se les pide para lo que solemos vernos obligados a introducir código en todos nuestros métodos.

Generar un log con el tiempo que un método tarda en ejecutarse es muy simple. Tan sólo necesitamos un par de líneas de código:


public List<User> getAllUsers() throws DaoException { Date d = new Date(); List<User> users= null; try { // code log.debug("method time: " + (new Date().getTime() - d.getTime()) + " ms"); return users; } catch (Exception e) { log.error("Error al insertar un organismo - " + e.toString()); throw new DaoException(e, "error getting users..."); } }

Sin embargo, ¿qué sucede si tenemos un centenar de métodos para el acceso a base de datos? ¿Debemos ir uno a uno introduciendo esas líneas de código? Fácil pero laborioso.

Para simplificarnos la vida y evitar el copy/paste utilizaremos AOP en colaboración con Spring. Con AOP podremos logar los tiempos de todos de cada uno de nuestros métodos sin necesidad de ir método a método copiando y pegando las líneas de código anteriores.

Lo primero que necesitamos es importar las librerías necesarias para ello (nos centraremos sólo en las librerías AOP dejando a un lado el resto de librerías, tales como las librerías de Spring)


<!-- AOP --> <dependency> <groupId>cglib</groupId> <artifactId>cglib-nodep</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.12</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.12</version> </dependency>


Seguidamente, creaemos nuestros aspecto y un "advice" de tipo "around" que será el que calcule el tiempo de ejecución de nuestros métodos:


package es.whatabout.service.db.aop; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.springframework.stereotype.Component; import org.springframework.util.StopWatch; @Aspect @Component public class Performance { private final Log log = LogFactory.getLog(Performance.class); /** * http://tomasjurman.blogspot.com.es/2010/01/spring-aop-with-annotation.html * * @param joinPoint * @return object * @throws Throwable */ @Around("execution(* es.whatabout.dao.*.* (..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { StopWatch clock = new StopWatch("performance_dao"); try { clock.start(); log.debug("Comenzando metodo: " + joinPoint.getSignature().getName()); return joinPoint.proceed(); } finally { clock.stop(); log.debug("Consumo: " + clock.prettyPrint()); } } }


No olvidemos declarar nuestra clase como un Aspecto y un Componente. Destacar también, en en la declaración del punto de corte hemos indicado que queremos que el advice se ejecute para todas las clases y métodos (*.*) del paquete es.whatabout.dao sean cuales sean cuales sean su parámetros ( (...) ) o retorno (*)

Por último, sólo queda configurar Spring correctamente de la siguiente forma:


<sws:annotation-driven /> <aop:aspectj-autoproxy proxy-target-class="true" /> <!-- enable component scanning (beware that this does not enable mapper scanning!) --> <context:component-scan base-package="es.whatabout.*" /> <!-- enable autowire --> <context:annotation-config />


Limpio y rápido. Si además, mañana queremos eliminar por completo cualquier log sobre tiempos, sólo debemos cambiar la configuración.

Tras el proxy

Trabajar tras un proxy siempre es un problema. Desde mi punto de vista todos son desventajas ya que pierdo más tiempo luchando con éste que el tiempo que éste me pueda salvar evitando que entre en páginas "no autorizadas" pero está claro que a veces no hay opción.

Cuando estamos, como es en mi caso, trabajando tras un proxy y necesitamos que nuestro código se conecte a servicios que se encuentras más allá del proxy, nos vemos obligados a configurar nuestro código para entenderse con proxys. Esta tarea es bastante simple, ya que según la documentación solo es necesario definir algunas variables del sistema:

  • http.proxyHost: pombre host del servidor proxy
  • http.proxyPort: puerto, siendo su valor por defecto 80
  • http.nonProxyHosts: listado de host que deben ser accedidos directamente, saltándose el proxy.

En este punto, podemos ver que ni siquiera es necesario modificar una sóla línea de código sino sólo proporciar dichas variables en el arrache de nuestra aplicación o servidor si trabajamos con una aplicación Web.

Sin embargo, la configuración no queda ahí sino que se complica un poco para los casos en los que necesitemos autenticarnos contra el proxy. Para estos casos es necesario trabajar con la clase Authenticator que como se puede leer en la documentación, representa un objeto que sabe cómo obtener autentificación para una conexión de red. Una instancia concreta de esta clase (según nuestras necesidades) debe registrase en el sistema llamando al método setDefault(Authenticator) para qué este esté disponible.

Así pues, lo primero que debemos hacer es crear nuestra instancia extendiendo de la original:

package es.whatabout.common.security; import java.net.Authenticator; import java.net.PasswordAuthentication; /** * * @author whatabout.es * */ public class ProxyAuthenticator extends Authenticator { private String username, password; public ProxyAuthenticator(String username, String password) { this.username = username; this.password = password; } protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password.toCharArray()); } }

A continuación debemos, como dijimos antes, registrar nuestro autenticador dentro de nuestro código antes de realizar las conexiones que necesiten autenticarse:

Authenticator.setDefault(new ProxyAuthenticator("user", "pass"));


Como vemos, trabajar tras un proxy no es dependiente de la tecnología, o de framework. Pero veamos un ejemplo de cómo se configuraría con Spring IoC un proxy que requiera autenticación.

Primero, declaramos el bean:

<bean name="simpleAuthenticator" class="es.whatabout.common.security.ProxyAuthenticator" autowire-candidate="true"> <constructor-arg index="0" value="#{systemProperties['user'] == null ? 'user' : systemProperties['user']}" /> <constructor-arg index="1" value="#{systemProperties['pass'] == null ? 'pass' : systemProperties['pass']}" /> </bean>


El nombre de usuario y la contraseña podría proporcionarse directamente en la declaración pero eso no sería muy portable además de verte obligado a escribir tu usuario y contraseña en un código que puede compartirse en un repositorio. Y puesto que ya son varias las variables de sistema que necesitamos, ¿por qué no proporcionar el usuario y la contraseña como variables del sistema? Otra particularidad que se puede apreciar en la declaración del bean es que se proporciona unos valores por defecto para el usuario y contraseña. Eso es necesario ya que si nuestra aplicación, según el entorno, no se encontrara tras un proxy y no proporcionáramos unos valores a través de las variables del sistema, la instanciación del bean daría error.

Segundo, utilizamos nuestra clase (inyectada previamente):


if (proxyAuthenticator != null) Authenticator.setDefault(proxyAuthenticator);


Finalmente, ejecutemos nuestra aplicación en local utilizando Maven y el plugin disponible para Jetty

mvn jetty:run -DproxySet=true -DproxyHost=proxy.indra.es -DproxyPort=8080 -Duser=XXX -Dpass=XXX 

¿Que pasa si la aplicación se desplegara en un entrono si proxy? ¿Hay que hacer algún cambio? No. Simplemente, no serían necesarias las variables del sistema:

mvn jetty:run

Si trabajamos con Maven, como en el ejemplo, también podríamos configurar estas variables de sistema en el plugin de Jetty y definiras en un perfil de forma que no nos veamos obligados a escribir las variables de sistemas cada vez que queramos ejecutar nuestra aplicación tras un proxy.

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.