18 July 2016

Extending WSO2 ESB with custom XPath functions

En este artículo voy a explicar como añadir funciones XPath para que puedan ser usadas en nuestras mediaciones de WSO2, y así poder extender su funcionalidad para adaptarse a nuestras necesidades.

Para lograr esto hay que crear un projecto maven java, el fichero jar resultante hay que copiarlo en $ESB_HOME/repository/component/dropins (si es un projecto OSGI) o $ESB_HOME/repository/component/lib(si es un fichero jar), posteriormente hay que registrar nuestra clase en el fichero ESB_HOME\repository\conf\synapse.properties

synapse.properties
synapse.xpath.func.extensions=edu.emmerson.synapse.extension.DemoFunctionProvider,...otros mediators...
En cuanto al projecto maven hay que añadir las siguientes dependencias en el fichero pom.xml.
<properties>
 <carbon.kernel.version>4.4.1</carbon.kernel.version>
 <carbon.mediation.version>4.4.12</carbon.mediation.version>
 <synapse.version>2.1.0</synapse.version>
</properties>
<dependencies>
 <dependency>
  <groupId>org.wso2.carbon</groupId>
  <artifactId>org.wso2.carbon.core</artifactId>
  <version>${carbon.kernel.version}</version>
 </dependency>
 <dependency>
  <groupId>org.wso2.carbon</groupId>
  <artifactId>org.wso2.carbon.registry.core</artifactId>
  <version>${carbon.kernel.version}</version>
 </dependency>
 <dependency>
  <groupId>org.apache.synapse</groupId>
  <artifactId>synapse-core</artifactId>
  <version>${synapse.version}</version>
 </dependency>
 <dependency>
  <groupId>org.wso2.carbon.mediation</groupId>
  <artifactId>org.wso2.carbon.mediation.initializer</artifactId>
  <version>${carbon.mediation.version}</version>
 </dependency>
</dependencies>
En nuestro código fuente necesitamos dos clases.

La siguiente clase implementa de SynapseXpathFunctionContextProvider, la cual registraremos en el fichero synapse.properties, en esta clase asignaremos un "namespace" y un "nombre" a nuestra función XPath con el cual haremos referencia en nuestras mediaciones, en este caso demo y myfunction.
package edu.emmerson.synapse.extension;

import javax.xml.namespace.QName;
import org.apache.synapse.MessageContext;
import org.apache.synapse.util.xpath.ext.SynapseXpathFunctionContextProvider;
import org.jaxen.Function;

public class DemoFunctionProvider implements SynapseXpathFunctionContextProvider {

 private static final String NAME_SPACE_PREFIX = "demo";
 private static final String MY_FUNCTION = "myfunction";

 public Function getInitializedExtFunction(MessageContext messageContext) {
  DemoFunction resolver = new DemoFunction(messageContext);
  return resolver;
 }

 public QName getResolvingQName() {
  return new QName(null, MY_FUNCTION, NAME_SPACE_PREFIX);
 }
}
La segunda clase es la implementación de la funcionalidad que queremos añadir y esta clase necesita implementar la interface Function, en este caso añade el prefijo Hello al parámetro recibido.
package edu.emmerson.synapse.extension;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.synapse.SynapseConstants;
import org.jaxen.Context;
import org.jaxen.Function;
import org.jaxen.FunctionCallException;
import org.jaxen.function.StringFunction;

public class DemoFunction implements Function {

 private static final Log log = LogFactory.getLog(DemoFunction.class);
 private static final Log trace = LogFactory.getLog(SynapseConstants.TRACE_LOGGER);
 public static final String NULL_STRING = "";
 private final org.apache.synapse.MessageContext synCtx;

 public DemoFunction(org.apache.synapse.MessageContext synCtx) {
  this.synCtx = synCtx;
 }
 
 public Object call(Context context, List args) throws FunctionCallException {
  String argOne = StringFunction.evaluate(args.get(0), context.getNavigator());
  try {
   String val = "Hello " + argOne;
   return val;
  } catch (Exception msg) {
   throw new FunctionCallException(msg);
  }
 }
}
Finalmente en nuestra secuencia del ESB podemos usarla como en el siguiente ejemplo.
<property description="calling custom xpath function"
        expression="demo:myfunction('readers')" name="myProperty"
        scope="default" type="STRING"/>
<log level="custom">
    <property expression="get-property('myProperty')" name="myProperty"/>
</log>
Después de ejecutar nuestro código podremos ver en el log como se añadio el prefijo Hello al parámetro readers.
[2016-07-17 23:16:20,925] DEBUG - SequenceMediator Mediation started from mediator position : 0
[2016-07-17 23:16:27,656]  INFO - LogMediator myProperty = Hello readers

- Enjoy -

19 June 2016

Code quality in WSO2 projects with SonarQube

Una de las principales preocupaciones en todo proyecto de desarrollo es la deuda técnica (a.k.a technical debt), y los proyectos con WSO2 no son la excepción, en muchos productos de su "Suite" el desarrollo se basa en ficheros xml, pero...

¿Como verificar la cálidad de estos desarrollos?


La respuesta es sencilla, utilizando SonarQube y una forma rápida de empezar es usando su "XML Plugin" para crear "custom XPath Rule".


¿Qué empezamos a validar?

La respuesta sigue siendo sencilla, entre otras cosas las "Best Practices for Mediation" que WSO2 tiene publicadas. Como se puede ver en la siguiente imagen, para este post he elegido la implementación de una de ellas.


Finalmente, como resultado del análisis de nuestros proyectos podemos obtener reportes completos de las malas prácticas y la localización exacta de cada una de ellas.

Enjoy!!!
- FIN -