Thursday, October 18, 2012

ServiceMix ESB: Http Connector Component

HttpConnector in ServiceMix is very useful component.

Now, i am going  to show you about how to make an HttpConnector in ServiceMix enabled application.

There is nothing to do much more to create this component.

You should need to follow below steps and enjoy with facilities provided by the HttpConnector.

First of all you have to more specific and clarity with  your requirement and decide whether this component is useful or not.

Steps to configure the in-built component of the ServiceMix.

Step : 1 Servlet entry in web.xml
Here, you have to make an entry for your HttpConnector component.
Below is the code snippet for web.xml,
      <servlet>
        <servlet-name>extreme</servlet-name>
        <servlet-class>org.apache.servicemix.components.http.SpringBindingServlet</servlet-class>
         <init-param>
             <param-name>endpoint</param-name>
             <param-value>ExtremeHttpConnector</param-value>
         </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>extreme</servlet-name>
        <url-pattern>/extreme/*</url-pattern>
    </servlet-mapping>


After this we need to make an entry in ServiceMix configuration file where all other component resides.

Step : 2 Component Entry in configuration file
Now its time to add your component in config file where all other component resides.
Below is the code snippet,

<sm:activationSpec componentName="ExtremeHttpConnector" service="foo:AsiteDocumentReceiver" destinationService="foo:Your DestinationService">
                <sm:component>
                    <bean class="com.makhir.component.ExtremeHttpConnector" id="ExtremeHttpConnector">
                        <property name="defaultInOut" value="false"/>
                        <!--<property name="maxThreads" value="5"/> Number of instance of this components in jbi container-->
                    </bean>
                </sm:component>
            </sm:activationSpec>


Here, you can easily see that the componentName in config file is same as entry in web.xml.

Step : 3 HttpConnector java class
Now its time to do some coding for our component.

package com.makhir.component;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;

import javax.jbi.JBIException;
import javax.jbi.messaging.InOnly;
import javax.jbi.messaging.MessageExchangeFactory;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.jbi.servicedesc.ServiceEndpoint;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkManager;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.servicemix.components.http.HttpConnector;
import org.apache.servicemix.components.util.CopyTransformer;
import org.apache.servicemix.jbi.framework.ComponentContextImpl;
import org.dom4j.Document;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;


/**
 * This class handles the coming request for different type of documents publishing and processed
 * and pass to the relevant jbi component for further processing. This class uses some properties
 * file with respect to incoming document via http request for deciding the buyer-supplier integration.
 * @author Ashish Mishra 
 * @since 28-09-2012
 */
public class ExtremeHttpConnector extends HttpConnector{
    private boolean defaultInOut;
    private WorkManager workManager;
   
    public void setDefaultInOut(boolean defaultInOut) {
        this.defaultInOut = defaultInOut;
    }
   
    public boolean getDefaultInOut() {
        return defaultInOut;
    }
   
    public void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, JBIException {
        processInOut(request, response);
    }
   
    public void processInOnly(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException, JBIException {
        try {
            // Do some logic here to process the incoming request

           processDocuments(file, request, response);
        } catch (ExtremeGenericException e) {
            return;
        } catch (Exception e) {
            return;
        }
    }
   
    public void processInOut(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException, JBIException {
        try {
        //  
        } catch (Exception e) {
           return;
        }
}
    /**
     * This method process the incoming documents and publish it against respective integration flow.
     *
     * */
    private boolean processDocuments(File[] files, HttpServletRequest request) throws WorkException, Exception {
        try {
            ComponentContextImpl contextImpl = (ComponentContextImpl) getContext();
            workManager = contextImpl.getWorkManager();
            HashMap<String, String> headerElements = ExtremeHttpHelper.getRequestHeaders(request);
            Map cgiMap = ExtremeHttpHelper.getCGIParameters(request);
            for (int index = 0; index < documentList.size(); index ++) {
                HashMap<String, Object> argMap = new HashMap<String, Object>();
                
argMap.put("headers", headerElements.clone());
                
argMap.put("cgiMap", ((HashMap)cgiMap).clone());
                
argMap.put("document", files[i]);
                asignToWorkmanager(
argMap);
            }
            return true;
        } catch (WorkException e) {
            throw e;
        } catch (Exception e) {
            throw e;
        }
    }
    /**
     * This method will create a separate thread for multiple document processing
     * */
    private void asignToWorkmanager(final Map<String, Object> paramMap) throws WorkException, Exception{
        try {
            workManager.scheduleWork(new Work() {
                @Override
                public void run() {
                    try {
                        processDocument(paramMap);
                    } catch (Exception e) {
                        return;
                    }
                }
                @Override
                public void release() {
                    // TODO Auto-generated method stub
                }
            });
        } catch (WorkException e) {
            throw e;
        } catch (Exception e) {
            throw e;
        }
    }
   
    private boolean processDocument(File file, HttpServletRequest request, HttpServletResponse response) throws Exception{
        String host = request.getRemoteHost();
        NormalizedMessage inMessage = null;
        InOnly exchange = null;
        try {
            Document xmlDocument =  null; // Add code to convert xml doc from the file
            MessageExchangeFactory factory = getExchangeFactory();
            exchange = factory.createInOnlyExchange();
            inMessage = exchange.createMessage();
            getMarshaler().toNMS(exchange, inMessage, request);
            exchange.setInMessage(inMessage);
            // Need to add some code for customizing the proccess flow of your document
            getDeliveryChannel().send(exchange);

// control handover to destination service as we configured for this component
             return true;
        }  catch (IOException e) {
            if(exchange != null)
                fail(exchange, e);
        } catch (MessagingException e) {
            if(exchange != null)
                fail(exchange, e);
        }catch (Exception e) {
            if(exchange != null)
                fail(exchange, e);
        }
        return true;
    }


private void processDocument(Map<String, Object> paramMap) throws Exception{
       NormalizedMessage inMessage = null;
        InOnly exchange = null;
        try {
            Document xmlDocument =  null; // Add code to convert xml doc from the file
            MessageExchangeFactory factory = getExchangeFactory();
            exchange = factory.createInOnlyExchange();
            inMessage = exchange.createMessage();
            getMarshaler().toNMS(exchange, inMessage, request);
            exchange.setInMessage(inMessage);
            // Need to add some code for customizing the proccess flow of your document
            getDeliveryChannel().send(exchange);

// control handover to destination service as we configured for this component
             return true;
        }  catch (IOException e) {
            if(exchange != null)
                fail(exchange, e);
        } catch (MessagingException e) {
            if(exchange != null)
                fail(exchange, e);
        }catch (Exception e) {
            if(exchange != null)
                fail(exchange, e);
        }
        return true;
    }

}
----------------------------------------------------------

Thats it.
Now your control handover to destination service as we configured for this component.

Now to  execute this component you should make an http call to this http-connector  with your application url.


For example, http://localhost:8080/makhir/extreme?action=document

Here,  /extreme is for your component which you mapped in web.xml.

Well done........
 
Great works by you....

Enjoy ServiceMix as an ESB...   

If any queries or questions, please update.

Thanks,
Ashish Mishra  
 
 



  

Wednesday, September 26, 2012

ServiceMix ESB: Quartz Integration


ServiceMix: Enterprise Service Bus.

Here, I am showing that how you integrate the Quartz component with Apache ServiceMix.

I assume that you some knowledge about ServiceMix and its architecture. I give you higher over view of ServiceMix.

Apache ServiceMix is a runtime container for service-oriented architecture components, web services or legacy system connectivity services. It is one of the most mature, open-source implementations of an enterprise service bus and an Apache top-level project.

For more, you can visit on http://servicemix.apache.org









I am not going to in detail of ServiceMix and its component and its working style. You can easily refer from various blogs and websites.

Let’s start implementing the Quartz component your existing running application which uses Apache ServiceMix.

First download the quartz jar file from its official site. Here i have used quartz-1.5.2.jar and add this jar to your lib folder.

Please, add below entry into say servicemix.xml [e.g. config file where you have specified all your component in spring’s bean like passion],

--------------------------------------------
<sm:activationSpec componentName="QuartzSchedular" service="foo:QuartzSchedular"  destinationService="foo:extremeEmailNotifier">
<sm:component>
<bean class="com.makhir.ExtremeQaurtzSchedular" id="QuartzSchedular">
<property name="marshaler">
<bean class="org.apache.servicemix.components.quartz.DefaultQuartzMarshaler" />
</property>
<property name="triggers">
<map>
<entry>
<key>
<bean class="org.quartz.SimpleTrigger">
<property name="repeatInterval" value="30000" /><!--Time in which your component will start its execution-->
<property name="repeatCount" value="-1" />
</bean>
</key>
<bean class="com.makhir.quartz.ExtremeQuartzJob">
<property name="name" value="makhirJob" />
<property name="group" value="ServiceMix" />
</bean>
</entry>
</map>
</property>
</bean>
</sm:component>
</sm:activationSpec>
----------------------------------------------------


Now, it’s time create a full component which is our primary goal.
Below is sample code which you needs to make your component into a working condition,
-------------
public class ExtremeQuartzSchedular extends QuartzComponent{
private final Log log = LogFactory.getLog(ExtremeQuartzSchedular.class);
private Map triggers;
private SchedulerFactory factory;
private Scheduler scheduler;
private WorkManager workManager = null;
@Override
public void setScheduler(Scheduler scheduler) {
   this.scheduler = scheduler;
}*/
@Override
public void setMarshaler(QuartzMarshaler marshaler) {
super.setMarshaler(marshaler);
}
@SuppressWarnings("rawtypes")
@Override
public void onJobExecute(JobExecutionContext context) throws JobExecutionException {
log.debug("Enter : onJobExecute");
try {
ComponentContextImpl contextImpl = (ComponentContextImpl) getContext();
workManager = contextImpl.getWorkManager();
File pollDirectory = new File("C:\\makhir\\workspace\\XJavaTest\\xmls");
File[] files = pollDirectory.listFiles();
for(int index = 0; index < files.length; index ++){
initializeJob(files[index]);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/*public Map getTriggers(){
return this.triggers;
}
public void setTriggers(Map triggers){
this.triggers = triggers;
}*/
protected void initializeJob(final File processFile){
log.debug("Enter : initializeJob");
log.debug("Proccessed file name : " + processFile.getName());
try {
workManager.scheduleWork(new Work() {
@Override
public void run() {
try {
doJob(processFile);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void release() {
}
});
// this code is for handling the work to be handled via workmanager with additional feature listener
/*workManager.scheduleWork(new Work() {
@Override
public void run() {
try {
doJob(processFile);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void release() {
}
}, 1000, new ExecutionContext(), new ExtremeWorkListner());*/ 
// 1000(1 sec) miliseconds within this time work must be started otherwise work will be rejected with rejected exception
} catch (WorkException e) {
log.error("WorkException :  Error while initialzing the job, " + e.getMessage());
e.printStackTrace();
} catch (Exception e) {
log.error("Exception :  Error while initialzing the job, " + e.getMessage());
}
log.debug("Exit : initializeJob");
}
protected void doJob(File file) throws IOException{
log.debug("Enter : doJob");
InputStream inputStream = null;
try {
inputStream = new BufferedInputStream(new FileInputStream(file));
MessageExchangeFactory exchanageFactory = getExchangeFactory();
InOut outMessage = exchanageFactory.createInOutExchange();
NormalizedMessage message = outMessage.createMessage();
message.setProperty("toEmailid", new String("abc@xyz.com"));
message.setProperty("fromEmailid", new String("notifications@xyz.com"));
message.setProperty("emailSubject", new String("How are you?"));
message.setProperty("bodyContent", convertStreamtoString(inputStream)));
outMessage.setInMessage(message);
send(outMessage);
} catch (MessagingException e) {
log.error("MessagingException : There was a problem exchanging the message");
e.printStackTrace();
} catch (JBIException e) {
log.error("JBIException : There was a problem exchanging the message");
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace(); 
}
finally{
try {
if (inputStream != null)
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
log.debug("Exit : doJob");
}
@SuppressWarnings("unused")
private String convertStreamtoString(InputStream stream) throws IOException{
log.debug("Enter : convertStreamtoString");
StringBuffer buffer = new StringBuffer();
   byte[] b = new byte[4096];
   for (int n; (n = stream.read(b)) != -1;) {
     buffer.append(new String(b, 0, n));
   }
   String messageContent = buffer.toString();
   log.debug("Converted input stream to string : " + messageContent);
   log.debug("Exit : convertStreamtoString");
return messageContent;
}
}



--------------------------

Now I will describe you how this component works.

After doing all this stuffs, when you start your ServiceMix integrated server, the ExtremeQuartzSchedular executes with all the initialization done by ServiceMix itself.

Here, I have use this component for looking some directory from where files will be picked up and email their content to someone.

The NormalizedMessage will be sent to the destinationService as defined in config file.

Here, this message will send to extremeEmailNotifier.

That's it.

I will explain later on about extremeEmailNotifier which is basically for sending email.

Enjoy with ServiceMix.

Feedback and questions are welcome.

Regards,
Ashish Mishra (makhir)