Sunday, December 10, 2017

Spring - Execute a init method when initializing bean and destroying bean.

There are couple of ways to achieve this requirement.

First methodology
You can simply implements below interfaces in the bean

  • InitializingBean
  • DisposableBean
Then you have to override below methods respectively above interfaces. 

  • afterPropertiesSet()
  • destroy()
Note: You have to use registerShutdownHook (link) to see the effect of the destroy method.

Second methodology
In this scenario, I would like to introduce the way we can execute the custom method when initializing and destroying beans.

Initially, you have to implement custom methods for init and destroy as below
    public void myInit() {
        System.out.println("This is the custom init method");
    }
....
    public void myDestroy() {
        System.out.println("This is the custom destroy method");
    }

In the bean configuration file you have to tell to the Spring what are the init and destroy methods as below.
<beans>
    <bean id="student" class="com.home.model.Student" init-method="myInit" destroy-method="myDestroy">
        .....
    </bean>
.....
.....
</beans>

Enjoy...!!!


Tuesday, December 5, 2017

Spring - How to destroy beans when application shutdown? (registerShutdownHook)

If someone needs to destroy the beans when shutdown then application, what you need to do is:
  • Create a 'AbstractApplicationContext'
  • call the 'registerShutdownHook'
Find the below code for your reference

AbstractApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
context.registerShutdownHook();

Once this "registerShutdownHook()" method executes, it destroy the beans when down the application.


Enjoy..!!

Sunday, September 24, 2017

Lambda (Java 8) - Transfer one type of object to another type of object

We will assume that we have list of Students to convert into list of Persions.

public class Student {
    private String name;
    private String school;
    private int age;

    public Student(String name, String school, int age) {
        this.name = name;
        this.school = school;
        this.age = age;
    }

    // getters/setters should come here

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", school='" + school + '\'' +
                ", age=" + age +
                '}';
    }
}

public class Person {
    private String fullName;
    private int age;

    public Person(String fullName, int age) {
        this.fullName = fullName;
        this.age = age;
    }

    //getters/setters should come here

    @Override
    public String toString() {
        return "Person{" +
                "fullName='" + fullName + '\'' +
                ", age='" + age + '\'' +
                '}';
    }
}

In this article, I'm going to use functional interface call Funcation to achieve this.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class StudentApplication {
    public static void main(String[] args) {
        Function<Student, Person> functionStuToPer = student -> new Person(student.getName(), student.getAge());

        List<Student> students = Arrays.asList(
                new Student("Tharanga", "UOC", 22),
                new Student("Ruwan", "UOM", 24),
                new Student("Ruvini", "UOK", 20),
                new Student("Randika", "TOUC", 25),
                new Student("Amara", "UOR", 23)
        );

        List<Person> persons = convertStudentListToPerson(students, functionStuToPer);
        persons.forEach(System.out::println);

    }

    private static List<Person> convertStudentListToPerson(List<Student> students, Function<Student, Person> functions) {
        List<Person> persons = new ArrayList<>();
        for (Student student: students) {
            persons.add(functions.apply(student));
        }
        return persons;
    }
}


Enjoy...!!

Lambda (Java 8) - How to sort and filter array

In this article, I'm going to explain about the way we can sort and filter an array using lambda expressions.

TASK 1

We will assume that, we have a list of students as follows:
 List<Student> students = Arrays.asList(
         new Student("Tharanga", "UOC", 22),
         new Student("Ruwan", "UOM", 24),
         new Student("Ruvini", "UOK", 20),
         new Student("Randika", "TOUC", 25),
         new Student("Amara", "UOR", 23)
);

In this scenario, we will assume that we have to sort the students by name:

Initially, how we cater this without lambda expression:
Collections.sort(students, new Comparator<Student>() {
       @Override
       public int compare(Student o1, Student o2) {
           return o1.getName().compareTo(o2.getName());
       }
});

Now will cater this requirement with lambda expressions.
 Collections.sort(students, (o1, o2) -> o1.getName().compareTo(o2.getName()));

Note: Since 'Comparator' interface is a functional interface we can sort the object list as above.

TASK 2

In here, we will assume that we need to filter the students, name starting with 'R'

Without lambda expression we can achieve this as below.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class StudentApplication {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("Tharanga", "UOC", 22),
                new Student("Ruwan", "UOM", 24),
                new Student("Ruvini", "UOK", 20),
                new Student("Randika", "TOUC", 25),
                new Student("Amara", "UOR", 23)
        );

        Collections.sort(students, (o1, o2) -> o1.getName().compareTo(o2.getName()));

        printConditionally(students, new Condition() {
            @Override
            public boolean test(Student student) {
                return student.getName().startsWith("R");
            }
        });

    }

    private static void printConditionally(List<Student> students, Condition condition) {
        for (Student student: students) {
            if(condition.test(student)) {
                System.out.println(student);
            }
        }
    }
}

interface Condition {
    boolean test(Student student);
} 

How we achieve this using lambda expression.
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;

public class StudentApplication {
    public static void main(String[] args) {
        List<Student> students = Arrays.asList(
                new Student("Tharanga", "UOC", 22),
                new Student("Ruwan", "UOM", 24),
                new Student("Ruvini", "UOK", 20),
                new Student("Randika", "TOUC", 25),
                new Student("Amara", "UOR", 23)
        );

        Collections.sort(students, (o1, o2) -> o1.getName().compareTo(o2.getName()));

        printConditionally(students, student -> student.getName().startsWith("R"));

    }

    private static void printConditionally(List<Student> students, Predicate<Student> predicate) {
        for (Student student: students) {
            if(predicate.test(student)) {
                System.out.println(student);
            }
        }
    }
}

Note: Java 8, OFTB support many functional interfaces such as "Predicate". You can find more on here.

Note: Find more information about funcational interfaces here.

Lambda (Java 8) - Functional Interface

To write a lambda expression, the interface should have only one abstract method. If an interface has more than one abstract method, we cannot write lambda expression.

When we work as a team, someone creates an interface to write a lambda expression. Later, another team member can add another abstract method to that interface to fulfill his requirement. But in this scenario, that change will effect to the lambda expression and it will not work.

To avoid above scenarios, we need to tell specifically, this interface should have only one abstract method.

We have a lovely annotation to cater this requirement as @FunctionalInterface. It restricts the adding more than one abstract method to the interface.

Find the below sample:
@FunctionalInterface
public interface Greeting {
    String perform(String s) ;
}


Enjoy...!!

Lambda (Java 8) - How to use Runnable interface

In this article, I'm going to explain the way we can use lambda to implement the Runnable interface.

General scenario is below:
  
   ...
   Thread myThread = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("Printed inside runnable");
            System.out.println(Thread.currentThread().getId());
        }
   });
   myThread.start();
   ...
Below is the code segment, same above implementation with lambda.
   ...
        Thread myLambdaThread = new Thread(() -> {
            System.out.println("printed inside the lambda expression");
            System.out.println("Thread Id: " + Thread.currentThread().getId());
        });

        myLambdaThread.start();
   ...


  • Empty parentheses: because run() method doesn't allow any arguments.
  • If there is more than one line of the implementation, we need to write the implementation inside the curly brackets.


Note: Runable interface only one method call run(), so we can write lambda expression. If there is more than one method declaration inside a interface, we cannot write lambda expression.

Enjoy..!!

Saturday, September 23, 2017

Lambda (Java 8) - Interface Implementation

In this post, I'm going to describe the way, we use lamdba to 'Interface Implementation'.

Find the below steps:

1. Create an interface as below
public interface Greeting {
    void perform() ;
}

2. In lambda, you can implement the perform method as below
Greeting greeting = () -> System.out.println("Hello Greeting");

3. Then finally, you can invoke the perform method as below.
...
Greeting greeting = () -> System.out.println("Hello , Greeting");
greeting.perform();
...
In the above scenario, I used empty parentheses, it is because, it should be similar to the method signature.
For an example, If I declare the perform() as perform(String message), lambda expression should be as below.
Greeting greeting = (message) -> System.out.println("Hello " + message);

Note: Here we don't need to specify the parameter type, java automatically sets the relevant type.

When we have a return type, above sample should change like follows.

public interface Greeting {
    String perform(String message) ;
}
Lambda:
Greeting greeting = (message) -> "Hello " + message;
Then, when we execute the perform method, it returns a string value.

Note: If you have to pass a single parameter, you can remove the parentheses as below
Greeting greeting = message -> "Hello " + message;

Enjoy...!!

Sunday, August 6, 2017

Mule ESB - How to write a simple munit unit-test for a flow

In this post, I'm going to use pretty simple flow to demonstrate the 'munit' test.

For an example, we will assume that we have sub-flow as below
    <sub-flow name="decision-Sub_Flow1">
        <set-variable variableName="country" value="Sri Lanka" doc:name="Variable"/>
    </sub-flow>

In this sub-flow, what we do is, we are creating a flow variable call 'country' and setting the value as 'Sri Lanka'.

Steps to write a munit test for the above scenario.

Right click the 'src/text/munit' folder and New -> MUnit Test. Then you can set a proper name to the text file and then need to select the flow which we are going to test.

It will open-up the test-suite as below
<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:munit="http://www.mulesoft.org/schema/mule/munit" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:core="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd">

    <munit:config name="munit" doc:name="MUnit configuration"/>
    
    <spring:beans>
        <spring:import resource="classpath:demo-munit-test.xml"/>
    </spring:beans>
    
    <munit:test name="SubFlow1-test-suite-decision-Sub_Flow1Test" description="Test">
        <flow-ref name="decision-Sub_Flow1" doc:name="Flow-ref to decision-Sub_Flow1"/>
    </munit:test>
</mule>

In the above test-suite file, we can clearly see that 3 components such as munit-config, spring-beans, and munit-test.
1. munit-config - we are saying that this is a munit config file
2. spring-beans - we are importing the mule app which we are going to write a munit test.
3. munit-test -  the area where we write the test code.

In this example, we are setting the country name and need to check the value whether it is correct of not. So, we can use the 'assert-on-equals' to fulfill this requirement as below
<munit:assert-on-equals expectedValue="#['Sri Lanka']" actualValue="#[flowVars.country]" doc:name="Assert Equals" message="Did not get expected value. expected value is 'Sri Lanka' but received #[flowVars.country]"/>

expectedValue: need to give the expected value in here, in this example it would be 'Sri Lanka'.
actualValue: here we need to give the actual value. we have set the flow variable call country, so, we can access that value as '#[flowVars.country]'
message: if this test fails, what would be the message to print.

After added this final munit test suite as below
<?xml version="1.0" encoding="UTF-8"?>

<mule xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation" xmlns:munit="http://www.mulesoft.org/schema/mule/munit" xmlns:spring="http://www.springframework.org/schema/beans" xmlns:core="http://www.mulesoft.org/schema/mule/core" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.mulesoft.org/schema/mule/munit http://www.mulesoft.org/schema/mule/munit/current/mule-munit.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd">

    <munit:config name="munit" doc:name="MUnit configuration"/>
    
    <spring:beans>
        <spring:import resource="classpath:demo-munit-test.xml"/>
    </spring:beans>
    
    <munit:test name="SubFlow1-test-suite-decision-Sub_Flow1Test" description="Test">
        <flow-ref name="decision-Sub_Flow1" doc:name="Flow-ref to decision-Sub_Flow1"/>
        <munit:assert-on-equals expectedValue="#['Sri Lanka']" actualValue="#[flowVars.country]" doc:name="Assert Equals" message="Did not get expected value. expected value is 'Sri Lanka' but received #[flowVars.country]"/>
    </munit:test>
</mule>

Saved and 'Run MUnit suite'

You can see the log file as below
===============================================================
===========  Running  SubFlow1-test-suite.xml  test ===========
===============================================================
Running SubFlow1-test-suite-decision-Sub_Flow1Test
SUCCESS - Test SubFlow1-test-suite-decision-Sub_Flow1Test finished Successfully.
INFO  2017-08-06 12:31:02,615 [main] org.mule.construct.FlowConstructLifecycleManager: Stopping flow: demo-munit-testFlow
INFO  2017-08-06 12:31:02,615 [main] org.mule.processor.SedaStageLifecycleManager: Stopping service: demo-munit-testFlow.stage1
INFO  2017-08-06 12:31:02,721 [main] org.mule.construct.FlowConstructLifecycleManager: Stopping flow: decision-Flow
INFO  2017-08-06 12:31:02,722 [main] org.mule.processor.SedaStageLifecycleManager: Stopping service: decision-Flow.stage1
INFO  2017-08-06 12:31:02,921 [main] org.mule.construct.FlowConstructLifecycleManager: Stopping flow: SubFlow1-test-suite-decision-Sub_Flow1Test
INFO  2017-08-06 12:31:02,921 [main] org.mule.processor.SedaStageLifecycleManager: Stopping service: SubFlow1-test-suite-decision-Sub_Flow1Test.stage1
INFO  2017-08-06 12:31:03,123 [main] org.mule.lifecycle.AbstractLifecycleManager: Stopping model: _muleSystemModel
INFO  2017-08-06 12:31:03,153 [main] org.mule.module.http.internal.listener.DefaultHttpListenerConfig: Stopped listener on http://0.0.0.0:8086
INFO  2017-08-06 12:31:03,155 [main] org.mule.util.queue.QueueXaResourceManager: Stopping ResourceManager
INFO  2017-08-06 12:31:03,155 [main] org.mule.util.queue.QueueXaResourceManager: Stopped ResourceManager
Connected to localhost in port 54275
INFO  2017-08-06 12:31:03,269 [Thread-1] org.mule.munit.plugins.coverage.server.MunitCoverageServer: Coverage connection received from localhost - true
INFO  2017-08-06 12:31:03,270 [main] org.mule.lifecycle.AbstractLifecycleManager: Disposing RegistryBroker
INFO  2017-08-06 12:31:03,274 [main] org.mule.construct.FlowConstructLifecycleManager: Disposing flow: demo-munit-testFlow
INFO  2017-08-06 12:31:03,277 [main] org.mule.processor.SedaStageLifecycleManager: Disposing service: demo-munit-testFlow.stage1
INFO  2017-08-06 12:31:03,278 [main] org.mule.construct.FlowConstructLifecycleManager: Disposing flow: decision-Flow
INFO  2017-08-06 12:31:03,278 [main] org.mule.processor.SedaStageLifecycleManager: Disposing service: decision-Flow.stage1
INFO  2017-08-06 12:31:03,278 [main] org.mule.construct.FlowConstructLifecycleManager: Disposing flow: SubFlow1-test-suite-decision-Sub_Flow1Test
INFO  2017-08-06 12:31:03,278 [main] org.mule.processor.SedaStageLifecycleManager: Disposing service: SubFlow1-test-suite-decision-Sub_Flow1Test.stage1
INFO  2017-08-06 12:31:03,280 [main] org.mule.lifecycle.AbstractLifecycleManager: Disposing model: _muleSystemModel
[org.mule.munit.remote.CoverageManager]accumulating report
[org.mule.munit.remote.CoverageManager]report is not null
INFO  2017-08-06 12:31:03,297 [Thread-1] org.mule.munit.plugins.coverage.server.MunitCoverageServer: Waiting for coverage connection 
INFO  2017-08-06 12:31:03,403 [main] org.mule.munit.runner.spring.config.MunitApplicationContext: Closing org.mule.munit.runner.spring.config.MunitApplicationContext@553f1d75: startup date [Sun Aug 06 12:30:57 IST 2017]; root of context hierarchy
INFO  2017-08-06 12:31:03,590 [main] org.mule.DefaultMuleContext: 
**********************************************************************
* Mule Context shut down normally on: 8/6/17 12:31 PM                *
* Server was up for: 0 days, 0 hours, 0 mins, 1.386 sec              *
**********************************************************************

===================================================================================
Number of tests run: 1 - Failed: 0 - Errors: 0 - Skipped: 0 - Time elapsed: 0.185ms
===================================================================================

Enjoy..!!

Thursday, July 20, 2017

Mule ESB - How to read JSON payload content?

In this blog, I'm going to explain how to read json payload in the mule flow.

For an example, we will assume that json payload receives as below
{
    "persons": [{
            "person": {
                "name": "Tharanga Wijeweear"
            }
        }]
}

You have to use the JSON prefix to access the json payload.

If you need to access the name of the first person, you need to write the mule expression as below.
#[json:persons[0]/person/name]

You can use the same steps followed in the previous blog (Mule ESB - How to read JSON payload content?)

Enjoy..!!

Mule ESB - How to read xml payload content?

In this blog, I'm going to explain the way we can access the XML payload content and assign into a variable.

For an example, we will assume that mule flow received a xml message as below
<persons>
    <person>
        <name>Tharanga</name>
        <city>Colombo</city>
        <address>
            <street>1st Cross Street</street>
            <postalCode>10250</postalCode>
            <country>Sri Lanka</country>
        </address>
    </person>
</persons>

If we need to read the name of the person, have to write a mule expression as below
#[xpath://persons/person/name]

Since this is a xml payload, we need to use the xpath prefix to access the payload.

I used below sample flow to check this scenario.
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
 xmlns:spring="http://www.springframework.org/schema/beans" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
    <http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8089" doc:name="HTTP Listener Configuration"/>
    <flow name="demo-readpayloadFlow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/payload" doc:name="HTTP"/>
        <set-variable variableName="messageid" value="#[xpath://persons/person/name]" doc:name="Variable"/>
        <logger message="#[flowVars.messageid]" level="INFO" doc:name="Logger"/>
        <set-payload value="#[flowVars.messageid]" doc:name="Set Payload"/>
    </flow>
</mule>

When invoking the flow, we can see the value in the console according to the above sample.
INFO  2017-07-21 09:24:16,065 [[demo-readpayload].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: Tharanga

Likewise, you can read the xml payload.

If the payload comes with the namespaces, you need to define the namespaces in the mulexml:namespace-manager tag as below
<mulexml:namespace-manager includeConfigNamespaces="true">
 <mulexml:namespace prefix="abc" uri="http://sample.lk/test" />
</mulexml:namespace-manager>
For an example, we will assume that payload comes as follows
<persons xmlns:abc="http://sample.lk/test">
    <abc:person>
        <abc:name>Tharanga</abc:name>
        <abc:city>Colombo</abc:city>
        <abc:address>
            <abc:street>1st Cross Street</abc:street>
            <abc:postalCode>10250</abc:postalCode>
            <abc:country>Sri Lanka</abc:country>
        </abc:address>
    </abc:person>
</persons>
And then need to change the mule expression as below
#[xpath://persons/abc:person/abc:name]

Likewise, you can read the xml payload when comes with the namespaces.

Enjoy..!!


Mule ESB - How to use batch element?

In this blog, I'm going to explain how to use the batch element in a flow.

In the Anypoint studio, you can search the batch element in the 'Mule Palette'. Once you drag and drop the 'Batch' element, you can see there are three (3) component on it.
1. Input
2. Process Records (In this step, you can have multiple steps)
3. On Complete

For this example, I'm going to use the 'Database element' as the input.

You cannot invoke the batch:job directly, so you have to use batch:execute to trigger the batch:job. In this example, I'm going to use the HTTP element to trigger this.

Find the blow configuration xml which I used to explain this.

<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:file="http://www.mulesoft.org/schema/mule/file" xmlns:db="http://www.mulesoft.org/schema/mule/db" xmlns:batch="http://www.mulesoft.org/schema/mule/batch" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
 xmlns:spring="http://www.springframework.org/schema/beans" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/db http://www.mulesoft.org/schema/mule/db/current/mule-db.xsd
http://www.mulesoft.org/schema/mule/batch http://www.mulesoft.org/schema/mule/batch/current/mule-batch.xsd
http://www.mulesoft.org/schema/mule/file http://www.mulesoft.org/schema/mule/file/current/mule-file.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
    <db:mysql-config name="MySQL_Configuration" host="localhost" port="3306" user="tharanga" password="tharanga" database="muledb" doc:name="MySQL Configuration"/>
    <http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8089" doc:name="HTTP Listener Configuration"/>
    <batch:job name="demo-batchBatch">
        <batch:input>
            <db:select config-ref="MySQL_Configuration" doc:name="Database">
                <db:parameterized-query><![CDATA[select * from student;]]></db:parameterized-query>
            </db:select>
        </batch:input>
        <batch:process-records>
            <batch:step name="Batch_Step1">
                <file:outbound-endpoint path="/home/tharanga/workspace/training/mule-esb/tmp/batch1" responseTimeout="10000" doc:name="File"/>
                <logger message="Step1 completed" level="INFO" doc:name="Logger"/>
            </batch:step>
            <batch:step name="Batch_Step2">
                <file:outbound-endpoint path="/home/tharanga/workspace/training/mule-esb/tmp/batch2" responseTimeout="10000" doc:name="File"/>
                <logger message="Step2 completed" level="INFO" doc:name="Logger"/>
            </batch:step>
        </batch:process-records>
        <batch:on-complete>
            <logger message="All steps are completed" level="INFO" doc:name="Logger"/>
        </batch:on-complete>
    </batch:job>
    <flow name="demo-batchFlow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/test" doc:name="HTTP"/>
        <batch:execute name="demo-batchBatch" doc:name="demo-batchBatch"/>
    </flow>
</mule>

Note:
In the above configuration I used 2 batch:process steps. In the first step I added the record to the batch1 directory and second steps used to add the record to the batch2 directory, using the file element.
To invoke the flow I used HTTP listener.

When invokes the flow, we can see the log as below.
....
INFO  2017-07-21 05:38:23,594 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch1/b6257190-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:23,594 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step1 completed
INFO  2017-07-21 05:38:23,595 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch1/b625bfb0-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:23,596 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step1 completed
INFO  2017-07-21 05:38:23,597 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch1/b6260dd0-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:23,597 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step1 completed
INFO  2017-07-21 05:38:23,611 [batch-job-demo-batchBatch-work-manager.04] com.mulesoft.module.batch.DefaultBatchStep: Step Batch_Step1 finished processing all records for instance b621c813-6da8-11e7-bae9-0242dea5cda5 of job demo-batchBatch
....
INFO  2017-07-21 05:38:34,038 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch2/bc5f3961-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:34,039 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step2 completed
INFO  2017-07-21 05:38:34,040 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch2/bc5f8780-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:34,041 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step2 completed
INFO  2017-07-21 05:38:34,045 [batch-job-demo-batchBatch-work-manager.04] org.mule.transport.file.FileConnector: Writing file to: /home/tharanga/workspace/training/mule-esb/tmp/batch2/bc604ad0-6da8-11e7-bae9-0242dea5cda5.dat
INFO  2017-07-21 05:38:34,046 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: Step2 completed
INFO  2017-07-21 05:38:34,050 [batch-job-demo-batchBatch-work-manager.04] com.mulesoft.module.batch.engine.DefaultBatchEngine: Starting execution of onComplete phase for instance b621c813-6da8-11e7-bae9-0242dea5cda5 of job demo-batchBatch
INFO  2017-07-21 05:38:34,050 [batch-job-demo-batchBatch-work-manager.04] org.mule.api.processor.LoggerMessageProcessor: All steps are completed
....
And finally, it also shows the summary of the process the as below (in the console)

INFO  2017-07-21 05:38:34,050 [batch-job-demo-batchBatch-work-manager.04] com.mulesoft.module.batch.engine.DefaultBatchEngine: Finished execution for instance 'b621c813-6da8-11e7-bae9-0242dea5cda5' of job 'demo-batchBatch'. Total Records processed: 3. Successful records: 3. Failed Records: 0

Enjoy..!!

Wednesday, July 19, 2017

Mule ESB - payload base64-encoding and base64-decoding

In this blog, I'm going to explain how to make our payload encoding and decoding.

You can use base64-encoder-transformer to encode the payload
<base64-encoder-transformer xmlns="http://www.mulesoft.org/schema/mule/core" encoding="utf-8"></base64-encoder-transformer>

You can use base64-decoder-transformer to decode the payload
<base64-decoder-transformer xmlns="http://www.mulesoft.org/schema/mule/core" encoding="utf-8"></base64-decoder-transformer>

Find the below sample flow to check the encoding and decoding mechanism.
<mule xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
 xmlns:spring="http://www.springframework.org/schema/beans" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd">
    <http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8089" doc:name="HTTP Listener Configuration"/>
    <flow name="demo-encode-decodeFlow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/sample" doc:name="HTTP" allowedMethods="POST"/>
        <logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
        <base64-encoder-transformer xmlns="http://www.mulesoft.org/schema/mule/core" encoding="utf-8"></base64-encoder-transformer>
        <logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
        <base64-decoder-transformer xmlns="http://www.mulesoft.org/schema/mule/core" encoding="utf-8"></base64-decoder-transformer>
        <logger message="#[message.payloadAs(java.lang.String)]" level="INFO" doc:name="Logger"/>
    </flow>
</mule>

Note: I used the logger component to print the encode and decode messages.

After making the POST request with a payload, we can see the below logs in the console:
INFO  2017-07-20 05:26:33,031 [[demo-encode-decode].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: Original Payload: ,{
  "id": "mule001",
  "name": "Mule course",
  "description": "Mule course Description"
}
INFO  2017-07-20 05:26:33,032 [[demo-encode-decode].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: base64-encoded message: ,ewogICJpZCI6ICJtdWxlMDAxIiwKICAibmFtZSI6ICJNdWxlIGNvdXJzZSIsCiAgImRlc2NyaXB0aW9uIjogIk11bGUgY291cnNlIERlc2NyaXB0aW9uIgp9
INFO  2017-07-20 05:26:33,032 [[demo-encode-decode].HTTP_Listener_Configuration.worker.01] org.mule.api.processor.LoggerMessageProcessor: base64-decoded message: ,{
  "id": "mule001",
  "name": "Mule course",
  "description": "Mule course Description"
}

Enjoy..!!

Mule ESB - How to undeploy a flow?

In this blog, I'm going to explain how to undeploy a flow in a clean way.

When we are starting a 'Anypoint studio', we have to choose the workspace.

For this explanation, we will assume that

1. our workspace as below
/home/tharanga/AnypointStudio/workspace
2. create a project as 'demo-http'

Once we run this application as 'Mule Application', we can see that, it creates the below file and folder inside the '/home/tharanga/AnypointStudio/workspace/.mule/apps' location.
drwxrwxr-x  5 tharanga tharanga 4096 ජූලි   19 19:58 demo-http/
-rw-rw-r--  1 tharanga tharanga   77 ජූලි   19 19:58 demo-http-anchor.txt

 To undeploy this flow, you can delete the <project_name>-anchor.txt file. According to this example file would be demo-http-anchor.txt

Note: anchor file location path would be <Anypoint_studio_workspace>/.mule/apps

Note: Inside the anchor file you can see the below content.
Delete this file while Mule is running to remove the artifact in a clean way.

Enjoy...!!