Tuesday, February 2, 2016

Xml to HTML Transformation using XSLT Transform in Mulesoft

Its pretty easy to transform Xml to HTML using Mulesoft's XSLT transform ..

Following is snapshot from my mule's config file ..















The Java component is used to provide following xml as an input :

<?xml version="1.0"?>
<catalog>
    <book id="bk101">
        <author>Gambardella, Matthew</author>
        <title>XML Developer's Guide</title>
        <genre>Computer</genre>
        <price>44.95</price>
        <publish_date>2000-10-01</publish_date>
        <description>An in-depth look at creating applications 
      with XML.</description>
    </book>
</catalog>
Following is the xsl code :
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" />
    <xsl:template match="catalog">
        <html>
            <body>
                <h2>My Book Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>Book</th>
                        <th>Genre</th>
                    </tr>
                    <xsl:for-each select="book">
                        <tr>
                            <td>
                                <xsl:value-of select="title" />
                            </td>
                            <td>
                                <xsl:value-of select="genre" />
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

We can notice that the output method is selected as html.











Once the flow is executed I can see the final html file being created in the output folder. 
I am using file:outbound-endpoint to write the contents in the output file ..



Monday, February 1, 2016

Xml to CSV Transformation using XSLT Transform in Mulesoft

I came across few questions on the internet on how to transform XML to CSV , HTML etc effectively in Mulesoft ..... So thought of trying out the Mule XSLT Transform .. It seems pretty cool and easy to use ... there could be some other better / effective ways but this also doesn't seem that bad ..

I downloaded pre existing xml (call me lazy ;)) from msdn and passed as an input to my xslt transform.  Xml snippet is as below .. its nothing but catalog of books:

<?xml version="1.0"?>
<catalog>
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
      <publish_date>2000-10-01</publish_date>
      <description>An in-depth look at creating applications 
      with XML.</description>
   </book>
   <book id="bk102">

As you can see in below snapshot .. I am pretty much using Java component (one can use some other component as well ..) to pass on the xml as an input.






My expected output is something like:

Author,Title,Genre,Price,
Gambardella Matthew,XML Developer's Guide,Computer,44.95,

So the magic happens as shown below.... the following is the code snippet from my xslt tranformer

<mulexml:xslt-transformer
maxIdleTransformers="2" maxActiveTransformers="5" doc:name="XSLT"

xsl-file="/Users/charlesparkhi/AnypointStudio/connectorws/xslt-usage/src/main/resources/XmlToCsv.xsl" />

Contents of XmlToCsv.xsl are :

<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method='text' />
<xsl:template match="catalog">
Author,Title,Genre,Price,
<xsl:text></xsl:text>
<xsl:for-each select="book">
<xsl:value-of select="author" />,<xsl:value-of select="title" />,<xsl:value-of select="genre" />,<xsl:value-of select="price" />,
<xsl:text></xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

I m then using file:outbound-endpoint to write the contents of final csv to a file ... named output.csv

<file:outbound-endpoint path="/MyPath/src/main/resources/output" outputPattern="output.csv" connector-ref="File" responseTimeout="10000" doc:name="File"/>

And Wallaah ... The csv is created :









Once opened I can see contents have been accurately represented ..




















Below is the code for this transformation :


<http:listener-config name="HTTP_Listener_Configuration"
host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration" />
    <file:connector name="File" writeToDirectory="/Users/charlesparkhi/AnypointStudio/connectorws/xslt-usage/src/main/resources/output" autoDelete="false" outputAppend="true" streaming="false" validateConnections="true" doc:name="File"/>
<flow name="xslt-usageFlow">
<http:listener config-ref="HTTP_Listener_Configuration"
path="/" doc:name="HTTP" />
<component class="com.test.xslttransform.InputProvider"
doc:name="Java" />
<mulexml:xslt-transformer
maxIdleTransformers="2" maxActiveTransformers="5" doc:name="XSLT"
xsl-file="/Users/charlesparkhi/AnypointStudio/connectorws/xslt-usage/src/main/resources/XmlToCsv.xsl" />
<byte-array-to-string-transformer doc:name="Byte Array to String"/>
<logger level="INFO" message="Final CSV #[payload]" doc:name="Logger"/>
        <file:outbound-endpoint path="/Users/charlesparkhi/AnypointStudio/connectorws/xslt-usage/src/main/resources/output" outputPattern="output.csv" connector-ref="File" responseTimeout="10000" doc:name="File"/>
<set-payload value="/" doc:name="Set Payload"/>
</flow>


Monday, January 18, 2016

Generate Unique Random Value using Function in Mule

Recently stumbled on a functionality in Mulesoft where I had to assign unique random Id to one of the variables in my code. Generally I would have used a Java component to generate UUID and assign the same to variable in Java itself.

But, Thanks to mule's intelligent MEL one doesnt have to write most of the stuff in Java. Following is the example.


<set-variable variableName="RandomValue" value="#[function:uuid]" doc:name="Variable" />

And ... That is it :) !!!!

I just wrote a small flow below to test it and seems to be pretty elegant solution ....



Executed multiple times from browser: http://http://localhost:8081/ and following is the result ... seems pretty unique !! .. Could be the smallest post on Mulesoft so far... :)



Tuesday, June 23, 2015

Mulesoft ESB Logging - Log messages in different files depending on message type

While working on Mulesoft I realized that sometimes its a requirement whereby one needs to log various types of inbound and outbound messages in different log files. This is really helpful you want to track huge load of messages coming in and going out of your mule flows.
     
This can be easily done in Mulesoft as the logging is mainly handled by Log4J implementation. So depending upon your Log4J configuration you can tweak your log setting just like any other java application.

In a following simple example we will see how the flow logs Inbound and Outbound messages in InboundMessage.log and OutboundMessage.log files.



Its a simple flow as shown in above image where inbound end point is http-connector .. we are doing some processing on the incoming message and then the payload is set for http-response. This http-response is outbound endpoint. One can use different types of endpoints from huge library of Mulesoft but the basic configuration remains the same.


As shown in the second image I have added a log4j config file. 

Note: I am using mule 3.6.1 here so I am using Log4J2 ... but one can use mule Log4J with previous versions of mule.

Following is my Log4j config file:

<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="warn" name="MyApp" packages="">
<Appenders>
         <File name="TraceFile" fileName="logs/appTrace.log">
                 <PatternLayout>
                        <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                 </PatternLayout>
         </File>
         
         <!-- file for inbound endpoint -->
         <File name="inboundLogs" fileName="logs/inboundLogs.log">
                <PatternLayout>
                      <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                </PatternLayout>
        </File>

        <!-- file for outbound endpoint -->
        <File name="outboundLogs" fileName="logs/outboundLogs.log">
                 <PatternLayout>
                       <Pattern>%d %p %c{1.} [%t] %m%n</Pattern>
                 </PatternLayout>
        </File>
</Appenders>

<Loggers>
        <!-- Jusgt for the Trace -->
        <Root level="trace">
               <AppenderRef ref="TraceFile" level="trace" />
        </Root>
       
       <!-- Assign logger for inbound messages -->
       <Logger name="com.mulemagic.demos.inboundlogs" level="debug">
                <AppenderRef ref="inboundLogs" level="debug" />
       </Logger>

       <!-- Assign logger for outbound messages -->
       <Logger name="com.mulemagic.demos.outboundlogs" level="debug">
                <AppenderRef ref="outboundLogs" level="debug" />
       </Logger>
</Loggers>
</Configuration>


In the above config file, I have mentioned two <File> tags under <Appenders> tag. Each File tag represents one log file with the messaging pattern.The <Loggers> section will add unique logger name for every file and this is where we will mark our loggers or direct messages to the already mentioned log files using logger name.

Now lets tie the inbound and outbound messages to these unique <Logger> in our mule config files ..Following is the exact Mule flow shown in the above image.

<http:listener-config name="HTTP_Listener_Configuration" host="0.0.0.0" port="8081" doc:name="HTTP Listener Configuration"/>
    <flow name="loggingexampleFlow">
        <http:listener config-ref="HTTP_Listener_Configuration" path="/" doc:name="HTTP"/>
        <logger level="DEBUG" category="com.mulemagic.demos.inboundlogs" message="Incoming message #[message.inboundProperties.'http.query.params']" doc:name="Logger" doc:description="This logger logs Inbound messages"/>
        <set-payload value="#[message.inboundProperties.'http.query.params']" doc:name="Set Payload"/>
        <logger level="DEBUG" category="com.mulemagic.demos.outboundlogs" message="Outgoing Message #[payload]" doc:name="Logger" doc:description="This logger logs Outbound messages"/>
    </flow>

Lets run the application and from browser I am sending a header parameter ..

http://localhost:8081/?state=BC 

Now once u run the application,  check the log folder in the project base directory.


In the InboundLogs.log we can see 

2015-06-23 18:54:14,241 DEBUG c.m.d.inboundlogs [[loggingexample].HTTP_Listener_Configuration.worker.01] Incoming message ParameterMap{[state=[BC]]}


And in OutboundLogs.log file we can see
2015-06-23 18:54:14,249 DEBUG c.m.d.outboundlogs [[loggingexample].HTTP_Listener_Configuration.worker.01] Outgoing Message ParameterMap{[state=[BC]]}


This is how we were able to successfully log Inbound and Outbound messages in respective files.


Monday, May 25, 2015

Mulesoft BIRT integration



I tried to check online how to integrate one of the best reporting framework BIRT Framework (http://eclipse.org/birt/) with one of the best ESBs i.e. Mulesoft (https://www.mulesoft.com/resources/esb/what-mule-esb) but couldn't find much. So after few trial and errors I could do some integration on my local and I thought its worth sharing it so writing this blog. This is my first ever tech blog so I hope doing it write ... if you have any questions then please do get in touch with me ...

The advantages of BIRT reports are


  1. The BIRT documentation is pretty extensive and well maintained.
  2. Because of its library features and easy to maintain .rptdesign files one can create complex and rich reports.
  3. Supports most of the file formats including PDF, HTML, SVG etc.


These advantages if combined with Mulesoft can give rich and complex reports for any type of business needs. For example if one needs to create a complex PDF report from the DB data using Mulesoft this is a good fit for it.

 In the following example we will be integrating reporting engine API with Mulesoft project and depending upon the inbound parameters we will be fetching the data for report and creating a PDF out of it.

I have used common Java component in this case but in future there is definitely a scope for addiing / creating BIRT connector from the Mulesoft.

In order to run this example we would need following items:



  1. MySQL (to fetch data from the report, one can use scripted datasource as well but I prefer to use    mysql for BIRT reports.)
  2. BIRT Reporting Engine runtime (download from http://download.eclipse.org/birt/downloads/#runtime)
  3. Anypoint Studio for Mulesoft Developement (download from https://www.mulesoft.com/studio)
First lets create a database and a table for the report ...


  • MySQL Setup:
mysql> create database mulesbirtint;
mysql> use mulesbirtint;

mysql> CREATE TABLE tech_companies (
  id int(10) unsigned NOT NULL AUTO_INCREMENT,
  name varchar(255) NOT NULL,
  ceo varchar(255) NOT NULL,
  hq varchar(255) NOT NULL,
  state varchar(20) DEFAULT NULL,
  PRIMARY KEY (id)
);

mysql> insert into tech_companies values 
(null,'Appnovation','Arnold Leung', 'Vancouver' , 'BC'),
(null,'Salesforce','Marc Benioff', 'San Francisco' , 'CA'),
(null,'Google' , 'Larry Page' , 'Mountain View' , 'CA'),
(null,'Facebook' , 'Mark Zukerberg' , 'Palo Alto', 'CA'),
(null,'Yahoo' , 'Marissa Mayer' , 'Sunnyvale' , 'CA');



  • Reporting Setup

  1. Create a Datasource

  1. Create dataset




  1. Create table





  • Mulesoft Setup
       Create flows and components as show in the below image. We will be creating an incound http endpoint and in its header we will pass value for the state. We will also have a Java component which will take the header (state) value from the eventContext and create a final PDF report output in the output folder of the project.




In the above picture we can see how the project has been setup in anypoint studio. The flow starts with http inbound endpoint , then there a logger to show the inbound parameters and then the Java component.The tech_companies.rptdesign file is kept in the reports folder.

Update the pom.xml to add BIRT dependencies in it ..

<dependency>
<groupId>org.eclipse.birt.runtime</groupId>
<artifactId>org.eclipse.birt.runtime</artifactId>
<version>4.3.0</version>
<exclusions>
<exclusion>
<groupId>org.eclipse.birt.runtime</groupId>
<artifactId>org.apache.poi</artifactId>
</exclusion>
<!-- <exclusion>
<groupId>org.eclipse.birt.runtime</groupId>
<artifactId>com.ibm.icu</artifactId>
</exclusion> -->
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>

<repositories>
<repository>
<id>sonatype-nexus-releases</id>
<name>Sonatype Nexus Releases</name>
<url>https://oss.sonatype.org/content/repositories/releases/</url>
</repository>
</repositories>


In the logger component add following message, it will print the state value passed from http request:

Request received .. generate report for state #[message.inboundproperties."http.request.params".state]

The Java component is calling the GenerateReport.java class which contains below code :

package com.appnovation.demos;

import org.mule.api.MuleEventContext;
import org.mule.api.lifecycle.Callable;
import java.util.logging.Level;

import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineException;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;
import org.eclipse.birt.report.engine.api.IReportRunnable;
import org.eclipse.birt.report.engine.api.IRunAndRenderTask;
import org.eclipse.birt.report.engine.api.PDFRenderOption;

public class GenerateReport implements Callable {

@Override
public Object onCall(MuleEventContext eventContext) throws Exception {

String param = eventContext.getMessage().getInboundProperty("state");
generateReportAsPerParam(param);
return "Report generation completed";
}

private void generateReportAsPerParam(String param) throws EngineException {

IReportEngine engine = null;
EngineConfig config = null;

try {
config = new EngineConfig();
config.setBIRTHome("/Users/username/Downloads/birt-runtime-4_4_2/ReportEngine");
config.setLogConfig("Users/username/test", Level.FINEST);
Platform.startup(config);
final IReportEngineFactory FACTORY = (IReportEngineFactory) Platform
.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
engine = FACTORY.createReportEngine(config);

// Open the report design
IReportRunnable design = null;
design = engine
.openReportDesign("reports/tech_companies.rptdesign");

IRunAndRenderTask task = engine.createRunAndRenderTask(design);
task.setParameterValue("param_1", param.toUpperCase());


// final HTMLRenderOption HTML_OPTIONS = new HTMLRenderOption();
// HTML_OPTIONS.setOutputFileName("output/final_report.html");
// HTML_OPTIONS.setOutputFormat("html");
// HTML_OPTIONS.setHtmlRtLFlag(false);
// HTML_OPTIONS.setEmbeddable(false);
// HTML_OPTIONS.setImageDirectory("C:\\test\\images");

PDFRenderOption PDF_OPTIONS = new PDFRenderOption();
PDF_OPTIONS.setOutputFileName("output/final_report.pdf");
PDF_OPTIONS.setOutputFormat("pdf");

task.setRenderOption(PDF_OPTIONS);
task.run();
task.close();
engine.destroy();
} catch (final Exception EX) {
EX.printStackTrace();
} finally {
Platform.shutdown();
}
}
}

Alright , now that the Muleproject is setup .. only thing remaining is to run it ...

Rightclick the project in Anypoint studio > Run As > Mule Application .... once the application is deployed .. go to any browser and invoke the http endpoint :

http://localhost:8081/?state=BC

Check the output folder in the project structure .. you can see the output report created final_report.pdf ....

let me know if you guys face any issues .... cheers !!