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 -

No comments: