WSO2

Tareas programadas a través del Enterprise Integrator

Además de ejecutar lógica a demanda, es posible que queramos tener ciertas lógicas que se ejecuten de forma periódica o en momentos puntuales. Para ello tenemos las tareas programadas o scheduled tasks.

A través del Enterprise Integrator, a partir de ahora EI, podremos crear tareas programadas que ejecuten nuestra lógica diferenciando en cómo y cuándo será ejecutada. A continuación veremos más en detalle estos dos aspectos que nos ayudarán a definirlas:

Cómo ejecutar tareas a través de Enterprise Integrator

Para ejecutar la tarea programada podemos crear nuestra propia clase Java que implemente la tarea que queramos realizar. Esta clase Java que debe implementar org.apache.synapse.task.Task, deberemos incluirla en una librería compatible con las ya existentes en el EI y además debe encontrarse dentro del directorio {EI_HOME}/dropins antes de que arranquemos el servidor.

Por otro lado, Synapse nos da la posibilidad de crear tareas a través de la consola de WSO2. Esta será una tarea predefinidas, con la que podremos invocar una secuencia o un proxy entre otros atributos. 

Pero a la misma vez, esta tarea predefinida es una clase Java denominada org.apache.synapse.startup.tasks.MessageInjector y la cual también implementa la clase Task. Creando la tarea a través de la consola de administración, nos evitaremos tener que reiniciar el servidor y tendremos un mayor control en el caso de que la programación Java no sea nuestro fuerte.

Cuándo ejecutamos tareas en Enterprise Integrator

A la hora de ejecutarla, podemos indicar que los tiempos para su ejecución a través de una expresión Cron. Con la cual tendremos un control mayor de cuándo la vamos a ejecutar y durante cuánto tiempo queremos ejecutarla. 

O podemos indicar de manera más simplificada, cuantas veces exactas queremos ejecutarla y con qué intervalo de tiempo entre las ejecuciones. 

Ejemplo de tarea ejecutada a través de Enterprise Integrator

A lo largo de un ejemplo vamos a ver como hacer una tarea programada con cada una de las opciones. Por un lado veremos una tarea con implementación Java y expresión Cron. Y por otro lado una tarea programada gestionada mediante Synapse y con ejecución simple.

En la tarea indicaremos los datos de un message processor ya configurado y comprobaremos si está funcionando o no. En un escenario más real podríamos realizar el envío de correos en caso de que el message processor no estuviese activo, pero para mantenerlo más simple, simplemente lo volveremos a activar. Para realizar todas estas operaciones, usaremos los servicios de administración de WSO2. El servicio de login para que se nos permita invocar al resto de servicios, y los métodos de ‘isActive’ y ‘activate’ del servicio de administración de los message processors.

Para evitar que los ejemplos sean demasiado extensos y en busca de la legibilidad, tendrán partes comentadas como puede ser la creación de los mensajes de los servicios de administración o código de utilidad que nos permite realizar las llamadas a los servicios.

Implementacion a través de Synapse

Antes de empezar el ejemplo, tenemos que saber a través de qué medio queremos crear nuestra tarea programada. A través de un proxy service o a través de una secuencia. Nosotros elegiremos la secuencia, puesto que nos permitirá simplificarlo aún más.

En nuestra secuencia, obtendremos los valores de entrada a través de property mediators, crearemos los mensajes para las llamadas con los payload factory mediators y realizaremos las llamada a través de los call mediators encapsulados en templates. Y no tendremos necesidad de indicar un respond o loopback mediator.

<sequence name="messageProcessorChecker" xmlns="http://ws.apache.org/ns/synapse">
    <property expression="$body/mc:mpChecker/mc:userName" name="userName" xmlns:mc="http://ws.apache.org/ns/sample" />
    <property expression="$body/mc:mpChecker/mc:userPass" name="userPass" xmlns:mc="http://ws.apache.org/ns/sample" />
    <property expression="$body/mc:processorName" name="processorName" xmlns:mc="http://ws.apache.org/ns/sample" />
    <payloadFactory media-type="xml">
        <format>
            <soap:Envelope xmlns:aut="http://authentication.services.core.carbon.wso2.org" xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
                <soap:Header/>
                <soap:Body>
                    <aut:login>
                        <aut:username>$1</aut:username>
                        <aut:password>$2</aut:password>
                        <aut:remoteAddress>localhost</aut:remoteAddress>
                    </aut:login>
                </soap:Body>
            </soap:Envelope>
        </format>
        <args>
            <arg evaluator="xml" expression="$ctx:userName" literal="false" />
            <arg evaluator="xml" expression="$ctx:userPass" literal="false" />
        </args>
    </payloadFactory>
    <call-template target="callAdminServices_temp">
        <with-param name="urlService" value="https://localhost:9443/services/AuthenticationAdmin"/>
        <with-param name="userName" value="$ctx:userName"/>
        <with-param name="userPass" value="$ctx:userPass"/>
        <with-param name="action" value="urn:login"/>
    </call-template>
    <!-- create payload for MessageProcessorAdminService with method isActivate -->
    <call-template target="callAdminServices_temp">
        <with-param name="urlService" value="https://localhost:9443/services/MessageProcessorAdminService"/>
        <with-param name="userName" value="admin"/>
        <with-param name="userPass" value="admin"/>
        <with-param name="action" value="urn:isActive"/>
    </call-template>
    <filter  xpath="//ns:return = 'false'">
        <then>
            <!-- create payload for MessageProcessorAdminService with method activate -->
            <!-- call MessageProcessorAdminService with method activate -->
        </then>
        <else />
    </filter>
</sequence>

Message: Campo obligatorio donde indicar un mensaje de entrada. Si queremos parámetros de entrada podemos pasarlos a través de este mensaje. Y si no queremos ninguno podemos simplemente poner un mensaje dummy, pero siempre hay incluirlo. Una vez tengamos correctamente creadas la secuencia y template asociados, pasaremos a la creación de la tarea programada. Las tareas programadas por Synapse son en realidad tareas Java predefinidas a la cual le pasamos unos determinados valores de entrada. Esta clase predefinida es org.apache.synapse.startup.tasks.MessageInjector y la cual también implementa la clase org.apache.synapse.task.Task. Al ser una tarea predefinida, tiene unos parámetros de entrada específico que hay que rellenar. Estos son: 

  • injectTo: Campo obligatorio donde debemos indicar si va a inyectar el mensaje en una secuencia, en un proxy, o en la secuencia principal por defecto ‘main’.
  • proxyName: Campo opcional donde se indica el nombre del proxy asociado, en función de si se ha seleccionado ‘proxy’ en el campo injectTo
  • secuenceName: Campo opcional donde se indica el nombre de la secuencia asociada, en función de si se ha seleccionado ‘sequence’ en el campo injectTo
  • To: Campo opcional donde podemos indicar un address endpoint
  • format: Campo opcional donde se indica el formato del address endpoint.
  • soapAction: Campo opcional donde se indica el soap action  para el address endpoint.

En el siguiente apartado indicaremos que tipo de programación queremos. Para este ejemplo usaremos la programación simple y para ellos deberemos rellenar los siguientes campos:

  • Count: Número de veces totales que queremos que se ejecute la secuencia
  • Interval: Intervalo en segundos de intervalo entre las ejecuciones de la tarea. 

De esta forma, como se puede apreciar, la configuración es más sencilla pero a la misma vez más limitada. 

Implementación a través de Java

Para realizar una tarea programada puramente Java, deberemos crear una clase que herede de org.apache.synapse.task.Task, que implemente el método execute y que realice dentro del mismo, la lógica deseada. 

Si queremos que la tarea programada tenga parámetros de entrada, debemos crear atributos de clase con sus correspondientes getters and setters. 

public class MessageProcessorCheckerTask implements Task {
  private final static String LOGIN_CALL = "<soap:Envelope xmlns:soap=\"http://www.w3.org/2003/05/soap-envelope\" xmlns:aut=\"http://authentication.services.core.carbon.wso2.org\">"
+ "<soap:Header/> <soap:Body> <aut:login>"
+ "<aut:username>%s</aut:username> <aut:password>%s</aut:password>"
+ "<aut:remoteAddress>localhost</aut:remoteAddress> </aut:login> </soap:Body> </soap:Envelope>";
  private final static String MP_ISACTIVE__CALL = "...";
  private final static String MP_ACTIVATE_CALL = "...";
  //input parameters
  private String urlService;
  private String userName;
  private String userPass;
  private String messageProcessorName;
  @Override
  public void execute() {
    // Login
    HttpUtil.getINSTANCE().postSecureSoap12(urlService + "/services/AuthenticationAdmin",
String.format(LOGIN_CALL, userName, userPass), userName, userPass, "urn:login");
    // Obtain if MP is active or not
  String response = HttpUtil.getINSTANCE().postSecureSoap12(urlService + "/services/MessageProcessorAdminService", String.format(MP_ISACTIVE__CALL, messageProcessorName), userName, userPass, "urn:isActive");
    // Get Response
    if (!Boolean.valueOf(ResponseUtil.getINSTANCE().getNsReturnValue(response))) {
      // Activate is it's not
      HttpUtil.getINSTANCE().postSecureSoap12(urlService + "/services/MessageProcessorAdminService", String.format(MP_ACTIVATE_CALL, messageProcessorName), userName, userPass, "urn:activate");
    }
  }
  //Getters and Setters
}

El siguiente paso será la creación de la tarea programada como tal. Para ello debemos indicar los siguientes valores:Una vez creada la clase, debemos empaquetarla como un fichero jar, incluirlo en la carpeta EI_HOME/dropins y reiniciar el servidor. 

  • Task Name: Nombre de nuestra tarea
  • Task Group: Grupo asociado de la tarea, por defecto synapse.simple.quartz.
  • Task Implementation: El nombre completo de nuestra clase. 

Tras indicar el nombre completo de nuestra  clase, pulsando sobre el botón ‘Reload Task Properties’, se creará una propiedad inferior por cada uno de los parámetros de la clase que tengan creado su método set. 

En el siguiente apartado debemos indicar que tipo de programación queremos para la tarea, la básica o la Cron. Por tanto, para este primer caso, debemos indicar una expresión Cron válida en el campo asociado. Este tipo de expresiones nos dará una potencia y capacidad de programación prácticamente ilimitada. 

Por último, en el caso de que nuestro EI estuviera clusterizado podríamos indicar el listado de nodos en los cuales se desea ejecutar la tarea programada. 

A través de estos ejemplos hemos podido ver como realizar tareas programadas fácilmente con el Enterprise Integrator. Como siempre la lógica puede ser más compleja en función de nuestras necesidades. Pero lo que debemos tener claro es que WSO2 nos ofrece múltiples herramientas y utilidades para la mediación de mensajes. 

daniel blanco
Written By

Daniel Santiago Blanco Cuadrado

Senior Integration Engineer