Tuesday, September 28, 2010

Liferay 6- Scheduler Engine design change


In Liferay 5.2.x, we had com.liferay.portal.kernel.job.IntervalJob as a Quartz scheduler job, which needs to be implemented for different jobs we need for Quartz trigger execution.

In Liferay 6, the design pf scheduler engine has been changed and introduced combination with JMS. I have prepared the small class cum collaboration diagram, which can help understanding how we need to make triggers now onwards.


Basically, they made use of messaging with Quartz. The Job class for liferay is now fixed which is com.liferay.portal.scheduler.job.MessageSenderJob .


Now we have a com.liferay.portal.kernel.messaging.MessageListener which is to be implemented for different job handling.

The schedulerEnginUtil class will register the listener with perticular queue destination and schedules new trigger as per the SchedulerEntry details with MessageSenderJob. When trigger fired, this Job class will eventually sends message to queue, which will eventually go to the listener.

This time, not as like previous scheduler, they have given exposure to Message which can contain some payload data if needed for job execution. This is very helpful sometimes.

By default the method schedule(SchedulerEntry schedulerEntry, ClassLoader classLoader)from SchedulerEngineUtil sends null Message. So, we might need to copy and pass some payload object if needed.

Tuesday, August 17, 2010

Liferay: Make Custom "Add Application" portlet ...

Sometimes client will amaze us by giving very very complex requirements which not seem to be a value adding thing. But still we need to complete it as it's our work :). Same happened here, when i need to make a portlet replicating the "Add Application" liferay portlet.

Though its not new, it has given me chance to see how "Add Application" menu works.

Basically liferay uses a Javascript file named layout_configuration.js to call the layout_configuration portlet.

Liferay has in-built portlet named layout_configuration for this functionality. It renders the same using LayoutConfiguration.toggle('87'); where 87 is the portlet ID.

Find the following portlet in file portal\portal-web\docroot\WEB-INF\liferay-portlet.xml,

 <portlet>  
         <portlet-name>87</portlet-name>  
         <icon>/html/icons/default.png</icon>  
         <struts-path>layout_configuration</struts-path>  
         <use-default-template>false</use-default-template>  
         <show-portlet-access-denied>false</show-portlet-access-denied>  
         <show-portlet-inactive>false</show-portlet-inactive>  
         <restore-current-view>false</restore-current-view>  
         <private-request-attributes>false</private-request-attributes>  
         <private-session-attributes>false</private-session-attributes>  
         <render-weight>50</render-weight>  
         <system>true</system>  
     </portlet>  

Also find the portlet in file \portal\portal-web\docroot\WEB-INF\portlet-custom.xml as below,

 <portlet>  
         <portlet-name>87</portlet-name>  
         <display-name>Layout Configuration</display-name>  
         <portlet-class>com.liferay.portlet.StrutsPortlet</portlet-class>  
         <init-param>  
             <name>view-action</name>  
             <value>/layout_configuration/view</value>  
         </init-param>  
         <expiration-cache>0</expiration-cache>  
         <supports>  
             <mime-type>text/html</mime-type>  
         </supports>  
         <resource-bundle>com.liferay.portlet.StrutsResourceBundle</resource-bundle>  
     </portlet>  

You will find the path layout_configuration in files struts-config.xml and tiles-defs.xml in the same folder.

In struts-config,

     <!-- Layout Configuration -->  
     <action path="/layout_configuration/templates" forward="portlet.layout_configuration.templates" />  
     <action path="/layout_configuration/view" forward="portlet.layout_configuration.view" />  

In tiles-defs,

 <!-- Layout Configuration -->  
 <definition name="portlet.layout_configuration" extends="portlet">  
     <put name="portlet_decorate" value="false" />  
 </definition>  
 <definition name="portlet.layout_configuration.templates" path="/portlet/layout_configuration/templates.jsp" />  
 <definition name="portlet.layout_configuration.view" extends="portlet.layout_configuration">  
     <put name="portlet_content" value="/portlet/layout_configuration/view.jsp" />  
 </definition>  

At first I started learning what liferay is doing. Basically in this portlet, liferay generates the HTML layout of all portlets in liferay-display.xml as per the category. It makes the whole tree structure of categories and subcategories. This portlet is not described in liferay-disaply.xml, so it will not be disaplayed in the tree.

Then it loads this portlet on onclick event of "Add Application" menu click. It calls the portal servlet at url /portal/render_portlet, which will render the portlet and shows the result HTML in popup dialog.

Check the javascript function from layout_configuration.js file,

 toggle: function(ppid) {  
         var instance = this;  
         var plid = themeDisplay.getPlid();  
         var doAsUserId = themeDisplay.getDoAsUserIdEncoded();  
         if (!instance.menu) {  
             var url = themeDisplay.getPathMain() + '/portal/render_portlet';  
             var popupWidth = 250;  
             var body = jQuery('body');  
             body.addClass('lfr-has-sidebar');  
             instance._dialog = Liferay.Popup(  
                 {  
                     width: popupWidth,  
                     message: '<div class="loading-animation" />',  
                     position: [5,5],  
                     resizable: false,  
                     title: Liferay.Language.get("add-application"),  
                     onClose: function() {  
                         instance.menu = null;  
                         body.removeClass('lfr-has-sidebar');  
                     }  
                 }  
             );  
             jQuery.ajax(  
                 {  
                     url: url,  
                     data: {  
                         p_l_id: plid,  
                         p_p_id: ppid,  
                         p_p_state: 'exclusive',  
                         doAsUserId: doAsUserId  
                     },  
                     success: function(message) {  
                         instance._dialog.html(message);  
                         instance._loadContent();  
                     }  
                 }  
             );  
         }  
     }  

After that, the javascript adds click and drag-drop even for all portlet divs of that popup dialog. So that user will be able to add the portlet into page by click OR drag-drop.

I need to show list of portlets of specified categories only without the categories.So i need to copy this portlet as it is and filter as per the category.

First of all i choosen the plugins environment for my new portlet, but it failed because i need to use the static resource named WebAppPool as per the code below,

PortletCategory portletCategory = (PortletCategory)WebAppPool.get(String.valueOf(company.getCompanyId()), WebKeys.PORTLET_CATEGORY);

This pool is maintained by liferay, it has all the categories on server startup. Now liferay loads the war file of plugin portlet when we add the portlet in page. So new classloader will be used here. And in java, child classloader can't access parent classloader's resources.

So i decided to move to ext environment. I made the new "Custom Add Application" portlet in ext with some code changes.

1. Need to filter the categories, for that i used portlet's init-param to define my including categories as below,

 <init-param>  
         <name>includeCategories</name>  
         <value>myCategory,yours</value> <!-- Comma seperated category names, sub-categories will not be filtered...-->  
     </init-param>  

2. Changed the code in view.jsp, included the categories only given in the init-param of above step and will show in HTML un-ordered list. Sent all categories to view_category.jsp.

3. Changed the code in view_category.jsp, displayed the portlets from all categories of above step as HTML list-items. It only shows portlets, ignoring the categories from view.

4. Same JS file has been used with different name to keep the drag-drop support for portlet list-items. Changed the JS file accordingly. Like ID for the result element is passed because now we don't want it to be in popup dialog etc...

5. Made new theme from classic, and changed the navigation.vm to show the above portlet as navigation menu item.

Though this was not extra-ordinary development, i got the chance to look into some internals of Liferay's odd style of developing a complex product, which may give us harsh times if touched :) (Isn't its too complex for a portal?).

Friday, July 30, 2010

Spring MVC portlet with annotations

Java portlet framework is awesome for portal developers. Different portal frameworks are there which supports portlet development in their environment. They also support spring portlet. Spring's portlet support is exposed through Spring MVC interface. Spring provides MVC based portlet development which is so easy and neatly architectured.

Spring provides class org.springframework.web.portlet.DispatcherPortlet which is to be difined in portlet.xml.
  <portlet>  
     <description xml:lang="en">Portlet Description</description>  
     <portlet-name>portlet-name</portlet-name>  
     <display-name xml:lang="en">Portlet Display Name</display-name>  
     <portlet-class>org.springframework.web.portlet.DispatcherPortlet</portlet-class>  
     <init-param>  
       <name>contextConfigLocation</name>  
       <value>/WEB-INF/appContext.xml</value>  
     </init-param>  
     <expiration-cache>0</expiration-cache>  
     <supports>  
       <mime-type>text/html</mime-type>  
       <portlet-mode>VIEW</portlet-mode>  
     </supports>  
     <portlet-info>  
       <title>Portlet Name</title>  
       <short-title>Portlet Name</short-title>  
       <keywords>Spring Portlet MVC</keywords>  
     </portlet-info>  
   </portlet>   

The init param contextConfigLocation defines the application context XML file to be loaded for this portlet. This file has the spring bean definition for classes implementing Controller interface OR annotated classes with @Controller.

Annotated Controller class is as follows,
 @Controller  
 @RequestMapping  
 public class MyController {  
   
     private static final Logger _LOG = Logger.getLogger(MyController.class);  
       
     //Default render method will call this method...  
     @SuppressWarnings("unchecked")  
     @RequestMapping({"VIEW","/demoportlet/jsp2.do"})  
     public Object defaultRender(Model model, PortletRequest request,RenderResponse response) {  
         response.setContentType("text/html; charset=UTF-8");  
         String action = request.getParameter("action");  
         if("action1".equals(action)) {  
              ...  
             return "demoportlet/jsp1";  
         } else {              
              ...  
             return "demoportlet/jsp2";  
         }  
     }  
       
     // Direct request mapping based on action parameter value = 'someAction'  
     @RequestMapping(params = "action=someAction")   
     public Object actionOne(RenderRequest actionRequest, RenderResponse actionResponse) throws Exception {  
         actionResponse.setContentType("text/html; charset=UTF-8");  
          ...          
         return "demoportlet/jsp2";  
     }  
 }  
   

In web.xml we need to define a servlet org.springframework.web.servlet.DispatcherServlet and org.springframework.web.servlet.ViewRendererServlet for JSP resolving as follows,

<servlet>  
     <servlet-name>view-servlet</servlet-name>  
     <servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>  
     <load-on-startup>1</load-on-startup>  
  </servlet>  
    
  <servlet>  
  <servlet-name>normal</servlet-name>  
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  <load-on-startup>1</load-on-startup>  
  </servlet>   
   
  <servlet-mapping>  
  <servlet-name>normal</servlet-name>  
  <url-pattern>*.do</url-pattern>  
  </servlet-mapping>   
    
  <servlet-mapping>  
     <servlet-name>view-servlet</servlet-name>  
      <url-pattern>/WEB-INF/servlet/view</url-pattern>  
  </servlet-mapping>  

In order for DispatcherPortlet rendering to work, you must declare an instance of the ViewRendererServlet .

In the Portlet MVC framework, each DispatcherPortlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. These inherited beans can be overridden in the portlet-specific scope, and new scope-specific beans can be defined local to a given portlet instance.

The DispatcherServlet will look for normal-servlet.xml as we declared its name as 'normal'. This file will contain the definitions for beans which are needed to handle the portlet scanning, annotation handling etc... So first of all, the request will come to DispatcherServlet as its Spring MVC, and then it will scan for portlet controllers using spring's <context:component-scan> tag.

We also need to define the context param contextConfigLocation in web.xml which is loaded by DispatcherServlet on server startup. This will have all the beans required by portlets.

 <context-param>  
  <description>Spring Context XML location</description>  
  <param-name>contextConfigLocation</param-name>  
  <param-value>classpath:conf/spring/global.xml</param-value>  
  </context-param>  

The normal-servlet.xml will look like follows, where we need to define beans for annotation handling.
 <beans xmlns="http://www.springframework.org/schema/beans"  
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:context="http://www.springframework.org/schema/context"  
     xmlns:util="http://www.springframework.org/schema/util"  
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
         http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd  
         http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">  
           
     <context:annotation-config />          
   
     <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">  
       <property name="cookieName" value="lang"/>  
       <!-- in seconds. If set to -1, the cookie is not persisted (deleted when browser shuts down) -->  
       <property name="cookieMaxAge" value="100000"/>  
     </bean>  
   
     <bean id="localeChangeInterceptor"  
    class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">  
       <property name="paramName" value="locale"/>  
     </bean>  
       
     <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">  
         <property name="interceptors">  
             <list>  
                 <ref bean="localeChangeInterceptor"/>  
             </list>  
         </property>  
         <property name="order" value="10" />  
     </bean>    
     
   <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>  
       
     <context:component-scan base-package="com.spring.controller" />      
 </beans>  
   

The <context:component-scan> will finds the controller classes from given package which are annotated with @Controller.

Other than is, we need to enter portlet information in portal framework's configuration files in which we want to deploy and use this portlet. When we add portlet from the portal, the controller methods will get call.

Wednesday, July 28, 2010

Display tag - Opensource JSP paging library...


Paging is important part when we have much data to show at once. We need to do all hectic coding for paging, like keep the total count, then count total pages to be shown, keep total records per page etc... This is nothing new but repeating and it takes bit time. So why not use some lib which gives you all of this with basic tags?

Note from the homepage : "The display tag library is an open source suite of custom tags that provide high-level web presentation patterns which will work in an MVC model. The library provides a significant amount of functionality while still being easy to use."

Basic steps to use are:

1. Get the jar file from http://displaytag.sourceforge.net and put it in classpath.

2. In your JSP page write following import for taglib.

 <%@ taglib uri="http://displaytag.sf.net" prefix="display" %>  

3. Check the following code for displaying the list of Objects as table with paging. You can configure different propeties of table as below, also can define CSS classes for diff. tags.


 <display:table name="lstObject" defaultsort="1" pagesize="20" sort="external" partialList="true"   
     size="totalCount" uid="lstObject" id="myObject"  
             export="false" requestURI="<%=someUrl%>" class="data">   
               
             <!-- For detailed understanding for each property, check the link http://displaytag.sourceforge.net/1.2/configuration.html -->  
             <display:setProperty name="paging.banner.placement" value="both" />  
             <display:setProperty name="paging.banner.group_size" value="10" />      
             <display:setProperty name="paging.banner.no_items_found">  
                 <span class="lfloat">No {0} found.</span>  
             </display:setProperty>  
             <display:setProperty name="paging.banner.one_item_found">  
                 <span class="lfloat">One {0} found.</span>  
             </display:setProperty>              
             <display:setProperty name="paging.banner.all_items_found">  
                 <span class="lfloat">{0} {1} found, displaying all {2}.</span>  
             </display:setProperty>  
             <display:setProperty name="paging.banner.some_items_found">  
                 <span class="lfloat">{0} {1} found, displaying {2} to {3}.</span>  
             </display:setProperty>              
             <display:setProperty name="paging.banner.full">  
                 <div class="paging_footer">  
                     <div class="rfloat">  
                         <div class="lfloat" style="padding-top:6px;">[<a href="{1}">First</a> | <a href="{2}">Prev</a>]</div>  
                         <div class="paging_wrap lfloat">                          
                             {0}                          
                         </div>  
                         <div class="rfloat" style="padding-top:6px;">[<a href="{3}">Next</a> | <a href="{4}">Last</a>]</div>  
                     </div>  
                 </div><br>  
             </display:setProperty>  
             <display:setProperty name="paging.banner.first">  
                 <div class="paging_footer">  
                     <div class="rfloat">  
                         <div class="lfloat" style="padding-top:6px;">[First | Prev]</div>  
                         <div class="paging_wrap lfloat">  
                              {0}  
                         </div>  
                         <div class="rfloat" style="padding-top:6px;">[<a href="{3}">Next</a> | <a href="{4}">Last</a>]</div>  
                     </div>  
                 </div><br>  
             </display:setProperty>          
             <display:setProperty name="paging.banner.last">                  
                 <div class="paging_footer">  
                     <div class="rfloat">  
                         <div class="lfloat" style="padding-top:6px;">[<a href="{1}">First</a> | <a href="{2}">Prev</a>]</div>  
                         <div class="paging_wrap lfloat">                          
                             {0}  
                         </div>  
                         <div class="rfloat" style="padding-top:6px;">[Next | Last]</div>  
                     </div>  
                 </div><br>  
             </display:setProperty>  
             <display:setProperty name="paging.banner.onepage" value="" /> <!-- Because dont want to show any value if only one page...-->  
               
             <display:setProperty name="paging.banner.page.selected">  
                 <div class="lfloat">  
                     <a onclick="return false;" class="active" href="javascript:void(0);">{0}</a>  
                 </div>  
             </display:setProperty>                      
             <display:setProperty name="paging.banner.page.link">  
                 <div class="lfloat">  
                     <a href="{1}" title="Goto page {0}">{0}</a>  
                 </div>  
             </display:setProperty>  
               
             <display:setProperty name="paging.banner.page.separator" value=" " />    <!-- Seperator between page numbers ,, i.e this will show "[First | Prev] 1 2 3 [Last | Next]"-->          
             <% MyObject myObject = (MyObject)pageContext.getAttribute("myObject"); %> <!-- Get the object from pageContext, which is writter in 'id' attribute -->  
              <display:column title="My title" class="first">  
              <!-- An y HTMl or jsp scriptlet can be used here... -->  
              </display:column>  
              <display:column property="name" title="2nd Column"/>  
              <display:column title="3rd Column"><%= myObject.getSomeValue() %></display:column>  
              ...               
         </display:table>  

4. The displaytag table can be used as follows. Where,

- pagesize is total records per page

- sort="external" means list given is sorted

- size defined the total records for which paging will be done

- name defines the list object for which the table will be generated

- id means internal object for each row which can be used in JSP scriptlets to do some data manipulations.

 <display:table name="lstObject" defaultsort="1" pagesize="20" sort="external" partialList="true"   
     size="totalCount" uid="lstObject" id="myObject"  
             export="false" requestURI="<%=someUrl%>" class="data">  
             ...  
             </display:table>  

5. You can set any property for display tag as below. You can also write HTML inside the property tag. For detailed understanding for each property this library supports, check the link - http://displaytag.sourceforge.net/1.2/configuration.html

 <display:setProperty name="paging.banner.page.separator" value=" " />

Wednesday, June 9, 2010

Liefray: Using JSONObject for Ajax in Plugin Portlet...

Many times we face situations when we need to use Ajax call from JSP pages. Using jQuery, its very easy to call any JSP through AJAX. You can just call the JSP and show its response from callback into some DOM element.

 $.ajax({  
      type: 'POST',  
      url: getUrl(),  
      data: {},                                   
      success: function(returnData) {  
          $('#someElementId').html(returnData);  
      }  
     });  

But this is useful when you want some big data OR some complex UI layout which is hard to generate using callback javascript function. Simple we call the JSP in which we have already designed the layout properly so we don't need to bother about manipulating the returnData in javascript.

Now think if you only need some small amount of data from server side, how will go? Making a new JSP for such a small task is not worhty i think. One technology is there for our help,JSON. JSON is a simple string notation of any object, which represents key-value pair like hashmap but uses its own structure to define objects.

Liferay provides com.liferay.portal.struts.JSONAction class which is a struts Action class. But to use this one in portlet we need to configure the portlet as a com.liferay.portlet. But there is one more way to use JSON with plugin portlet, using overriding serveResource method from GenericPortlet class into your portlet class.

 protected void getSomeDataAsJson(ResourceRequest request, ResourceResponse response)  
 throws PortletException, IOException {  
     String myParam = ParamUtil.getString(request, "myParam","");  
     // Some service call using params from request...  
     Obj obj = getDataFromSomeService(myParam);  
     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();  
     // obj can be anything... Integer,Boolean,String or some custom POJO...  
     jsonObj.put("testData", obj);  
     OutputStream os = response.getPortletOutputStream();  
     try {  
         os.write(jsonObj.toString().getBytes());  
     }  
     finally {  
         os.close();  
     }  
 }  
 @Override  
 public void serveResource(ResourceRequest request, ResourceResponse response)  
         throws PortletException, IOException {  
     String cmd = ParamUtil.getString(request,Constants.CMD);  
     if ("getSomeDataAsJson".equals(cmd)) {  
         getSomeDataAsJson(request, response);  
     }  
 }  

The above method will provide the JSON object as a result in javascript callback function. Check the Ajax call,

 $("input:button[@name='<portlet:namespace />SomeThing']").click (function() {  
     $('#<portlet:namespace />myDiv').text("");  
     //URL which goes to your portlet...  
     var url = "<portlet:resourceURL><portlet:param name='<%=Constants.CMD %>' value='getSomeDataAsJson' /></portlet:resourceURL>";      
     //Append your hidden input fields in the resourceURL...   
     url +="&"+$('input:hidden').serialize();   
     $.ajax({  
             url: url,  
             data: {},  
             dataType: 'json',  
             success: function(message) {  
                     $('#<portlet:namespace />myDiv').text(message.testData);  
                     }  
             }  
         );      
     });  

This way we don't need to create JSPs for small data fetching. Show other ways also using simple AJAX calling (Like DWR supports, direct calling JAVA class method from JS and returns data in JS callback).

Friday, June 4, 2010

Javascript-ajax RSS feed reader - using jQuery with jGFeed ...

Check the new version of Ajax feed reader, which is using jQuery with jGFeed.

 <html><head>  
 <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>  
 <script type= "text/javascript" language='javascript'>  
 //<![CDATA[  
 (function($) {  
   $.extend( {  
 jGFeed : function(url, fnk, num, key) {  
       // Make sure url to get is defined  
       if (url == null) return false;  
       // Build Google Feed API URL  
       var gurl = "http://ajax.googleapis.com/ajax/services/feed/load?v=1.0&callback=?&q="+url;  
       if (num != null) gurl += "&num="+num;  
       if (key != null) gurl += "&key="+key;  
       // AJAX request the API  
       $.getJSON(gurl, function(data) {  
         if (typeof fnk == 'function')  
           fnk.call(this, data.responseData.feed);  
         else  
           return false;  
       });  
     }  
   });  
 })(jQuery);  
 var strArr = ['http://www.thinkdigit.com/forum/external.php?type=RSS','http://www.snapfiles.com/feeds/sf20fw.xml',  
        'http://www.download.com/3410-2001-0-10.xml','http://www.download.com/3412-2001-0-10.xml',  
        'http://www.download.com/3412-2003-0-25.xml','http://www.videohelp.com/rss/tools',  
        'http://www.videohelp.com/rss/forum','http://www.pcstats.com/rss/rss.xml','http://feeds.feedburner.com/Techdudes',  
        'http://feeds.feedburner.com/jQueryHowto'];  
 var isXml = true;  
 function loadXml() {  
   var index = Math.floor(Math.random()*strArr.length);  
   getJsonData(strArr[index],'targetDiv');  
 }  
 //loadXml();  
 function getJsonData(dataSource, divId) {  
   $.jGFeed(dataSource,  
   function(feeds) {  
     if (!feeds) {  
       alert('there was an error');  
     }  
     var html = "";  
     for (var i=0;i<feeds.entries.length;i++) {  
       var entry = feeds.entries[i];  
       var title = entry.title;  
       var link = entry.link;  
       var description = entry.contentSnippet;  
       var pubDate = entry.publishedDate;  
       html += "<div class='entry'><h4 class='postTitle'><a class='fancy block' href='" + link + "' target='_blank'>" + title + "</a></h4>";  
       // html += "<em class='date'>" + pubDate + "</em>";  
       var categories = " Lables : ";  
       if (entry.categories && entry.categories.length>0) {  
         categories += entry.categories[0];  
         for (var j=1;j<entry.categories.length;j++) {  
           categories +=", " +entry.categories[j];  
         }  
         html += "<p><b>"+categories+"</b></p>";  
       }  
       html += "<p class='description'>" + description + "</p></div>";  
     }  
     var btn = "<input type='button' value='Reload' onclick='getJsonData(\""+dataSource +"\",\""+divId+"\");' /></br>";  
     $('#'+divId).html(btn + html);  
   },  
   50);  
 }  
 function cleartDiv(divId) {  
   var obj = document.getElementById(divId);  
   if (obj) {  
     //obj.style.display = 'none';  
     obj.innerHTML="";  
   }  
 }  
 function getNewData(url,divId) {  
   if (url!=0) {  
     if (!url) {  
       var index = Math.floor(Math.random()*strArr.length);  
       getJsonData(strArr[index],divId);  
     } else {  
       getJsonData(url,divId);  
     }  
   }  
 }  
 //window.setInterval("getNewData()", 7000); // update the data every 20 mins  
 //]]>  
 </script>  
 </head>  
 <body onload="getNewData('http://www.videohelp.com/rss/tools','targetDiv');">  
     <select onchange="javascript:getNewData(this.options[this.selectedIndex].value,'targetDiv');" size="9" style="width:25%;">  
         <option value='0' selected="selected">Please Select</option>  
         <option value='http://www.thinkdigit.com/forum/external.php?type=RSS'>ThinkDigit.com</option>  
         <option value='http://www.snapfiles.com/feeds/sf20fw.xml'>SnapFiles.com</option>  
         <option value='http://www.articlecity.com/xml/main.xml'>ArticleCity.com</option>  
         <option value='http://www.download.com/3410-2001-0-10.xml'>Download.com populars</option>  
         <option value='http://www.download.com/3412-2001-0-10.xml'>Download.com New</option>  
         <option value='http://www.download.com/3412-2003-0-25.xml'>Download.com 25 New Titles</option>  
         <option value='http://feeds.feedburner.com/Techdudes'>TechDudes</option>  
     </select>  
     <div id="linkDiv" style="width:98%;height:25px;overflow:auto;"/>  
     <div id="targetDiv" style="border:dashed 1px;background:#fafafa;width:70%;height:450px;overflow:auto;font-family:verdana;font-size:10px;"/>  
 </body>  
 </html> 
 
jGFeed: http://plugins.jquery.com/project/jgfeed 

Wednesday, June 2, 2010

jQuery - usage of $.bind method...

jQuery is widely used javascript library which provides easy ways to do complex things. By using simple Javscript, it takes too much time to code it, but jQuery simple it down to few lines.

To check multiple Checkboxes, i have written the following code.

 <script type="text/javascript" src="html/js/jquery.js"></script>  
 <script type="text/javascript">  
 //on load, register events for checkboxes...  
 $(document).ready(  
      function() {       
           $('#chk_all').change(checkAll);            
           $('form[@name="fm"] input:checkbox[@name!="chk_all"]').each (function(index) {  
                $(this).change(selectForDelete);  
           });  
      }  
 );  
 function checkAll(){  
      var isCheck = this.checked;  
      $('form[@name="fm"] input:checkbox[@name!="chk_all"]').each(function(){  
           this.checked = isCheck;  
           $(this).trigger("change");  
      });  
 }  
 function selectForDelete(){  
      var alertIdsObj = $('form[@name="fm"] input[@name="deleteIds"]');  
      if (this.checked) {  
           if (alertIdsObj.val().indexOf(this.value)==-1) {  
                if(alertIdsObj.val()=='') {  
                     alertIdsObj.val(''+this.value);  
                } else {  
                     alertIdsObj.val(alertIdsObj.val()+","+this.value);  
                }  
           }  
      } else {  
           if (alertIdsObj.val().indexOf(this.value)>=0) {  
                alertIdsObj.val(alertIdsObj.val().replace(this.value+',',''));  
                alertIdsObj.val(alertIdsObj.val().replace(','+this.value,''));  
                alertIdsObj.val(alertIdsObj.val().replace(this.value,''));  
           }  
      }  
 }  
 //Function called for item details...  
 function viewAlertDetails(alertId) {  
           $.ajax({  
            type: 'POST',  
            url: getUrl()+"&alertId="+alertId+"&cmd=detailed-market-alerts",  
            data: {},                                           
            success: function(returnData) {  
                 $('#-mainDiv').hide();  
                 $('#-detailsDiv').html(returnData);  
                 $('#-detailsDiv').show();       
            }  
           });       
 }  
 function getUrl() {  
      var url = new String(document.location);  
      var index = url.indexOf("?");  
      if (index!=-1) {  
           url = url.substring(0,index);  
      }  
      return url;  
 }  
 //function called from second page to go back to first page with latest data...  
 //Repalces the old content with new  
 function viewAlerts() {  
      $.ajax({  
            type: 'POST',  
            url: getUrl(),  
            data: {},                                           
            success: function(returnData) {       
                var myData = $(returnData).find('#-mainDiv').html();  
                $('#-mainDiv').html(myData);  
                $('#chk_all').bind('change', checkAll);  
                $('form[@name="fm"] input:checkbox[@name!="chk_all"]').each (function(index) {            
                     $(this).bind('change',selectForDelete);            
                });  
                $('#-detailsDiv').html("");  
                $('#-detailsDiv').hide();  
                $('#-mainDiv').show();  
                return true;  
            }  
           });       
      return false;  
 }  
 </script>  

The flow is as below,
- First page shows list of data.
- By clicking particular item from the list, i hides the mainDiv and shows details of the item in detailsDiv using $.ajax.
- By clicking "Back" button from detailsDiv, i again loads the main page using $.ajax.

The problem is, when i go to second page and comes on the first page using $.ajax,i change the HTML content of mainDiv with the latest data in viewAlerts() javascript function as $('#-mainDiv').html(myData);.

If you check the script, you will notice that i have registered the event handling for checkboxes in the document,One for main checkbox and one for all other checkboxes of the list, using $(document).ready() jQuery function. Event handling works fine at first page. But when we change the html content of the div afterwards, event handler automatically removed.

So to re-enable the events on checkboxes,we need to use following code in viewAlerts() javascript function.

 $('#chk_all').bind('change', checkAll);  
 $('form[@name="fm"] input:checkbox[@name!="chk_all"]').each (function(index) {  
      $(this).bind('change',selectForDelete);            
 });  

$(jQueryDomObj).bind(eventName,function) is very useful if you want to manipulate the element contents using javascript.

Thursday, May 27, 2010

Java Wildcards Vs. Generics...

I have never used wildcards in java until i read this.

Let's say I have a super class Vehicle and few sub classes like Scooter, Bike, Car, etc... Now I need to have a list of vehicles, my first thought would be something like:

 List<Vehicle> lstVehicles;

Instead, some people are recommending something like:

 List<? extends Vehicle> lstVehicles;

Why should I use wildcards instead of simple generics?

Because Java generics are invariant.

Suppose we have B extends A:

* B is a subtype of A
* an instanceof B is also an instanceof A

Since Java arrays are covariant:

* B[] is a subtype of A[]
* an instanceof B[] is also an instanceof A[]

However, Java generics are invariant:

* List<B> is NOT a subtype of List<A>
* a instanceof List<B> is NOT an instanceof List<A>.

Wildcards are used to make it more flexible while preserving type safety.

*
List<B> is a List<? extends A> 

References:
Wildcards
Generics
Generics and subtyping
More fun with wildcards

Friday, May 21, 2010

Java String manipulation: Appending empty string to 'var.subString(x,y)' saves memory...


In java usually we do SubString operation as follows.


    String strMainData = "Some long String..." ;
    String strSub= strMainData.subString(i,j); // Where i and j are index values...

This operation will keep the reference to same object strMainData,but only returns smaller string as per the indexes. So it uses same memory as the original String.

We should use it as follows.

    String strSub = new String(strMainData.subString(i,j));
OR

    String strSub = strMainData.subString(i,j) +"";
This will only keep the reference to new smaller String and removes reference to original String variable.



Singleton refactored:Initialization on demand holder idiom...

Hey guys, check this out. I found this while searching around different styles for singleton pattern. It basically provides on demand loading of the instance.

public class Something {
 private Something() {
 } 
 private static class LazyHolder {
  private static final Something INSTANCE = new Something();
 } 
 public static Something getInstance() {
  return LazyHolder.INSTANCE;
 }
}

The static class LazyHolder is only executed when the static method getInstance is invoked on the class Something, and the first time this happens the JVM will load and initialize the LazyHolder class. The initialization of the LazyHolder class results in static variable INSTANCE being initialized by executing the (private) constructor for the outer class Something.

More @ Wiki

Thursday, May 20, 2010

AXIS2 web service client - without sub/proxy ...

This article is regarding how to call an web service without modifying the client each time for diff. web service OR method call. Basically we use stub/proxy classes for diff. web service method calls using Axis2, but internelly it calls using XML SOAP envelopes. So, we can direcftly convert the client to use Axis2 API classes and provide an implementation which only needs to handle the response from the call. Response will be in XML format,so we need to fetch data from XML. We can covnert XML into Pojos using Castor or JAXB libs.

You can directly use ServiceClient class to call web service, which provides call using XML only and returns XML response. For different methods of web service, you have to convert the XML response to some java POJO to use it. Only Response handling needs to be done at your end. that you can do like from XML to Map etc...

So you won't need any other stub classes to call any web service, only needs to handle response XML or converted POJO.

This is the way you don't need to modify your client every time for diff. web services. You can develop like providing a response handler to client externally. So that for every different web service you will have diff. response handler class which is implementation of you interface.

//common interface for response handlers...
//implement this for diff. web service/methods

public interface WSRespHandler{
    public Object getMeResp(Object respData);
}

//pass particular handler to client when you call some WS
public class WebServiceClient {
    public Object getResp(WSRespHandler respHandler) {
        ...
        return repHandler.getMeResp(xmlData);
    }
}

References:

http://www.developer.com/java/web/article.php/3863416/Using-Axis2-and-Java-for-Asynchronous-Web-Service-Invocation-on-the-Client-Side.htm

http://www.devdaily.com/blog/post/java/java-web-service-client-read-array-list/

Facebook integration in your web application...

This is not regarding only java, you can do this on any web application in different languages also.

Facebook is getting popular now a days. Almost every site has facebook login enabled, so that if the user has facebook account he can login using that and can use the site as a registered user. For this the user must allow the site to use his facebook user data (Friends list, profile details etc...). Facebook provides different set of APIs to do such integration with your site.
 
It basically provides different client APIs which are based on different technologies lke PHP, Java, Javascript etc.. Here i will show you how to integrate facebook only using javascript API, which is the best way to do this.
 
    1. First step is, you have to include the javascript from FB as follows.  

        <script type="text/javascript"
        src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php"></script>
 
    2. You have to init the Facebook JS library with you facebook API key and provide the XDReceiver url. XDReceiver.htm is provided by facebook which is to be uploaded on you server to handle the callback to Facebook's javascript functions. It will store facebook cookies on your server so that you can access the facebook session in your site to fetch facebook data for the logged in user.    

        FB.init("myApiKey","/html/xd_receiver.htm", {
        "doNotUseCachedConnectState" : false
        ,"reloadIfSessionStateChanged" : true    //Reloads the page if user logs in OR out
        ,"ifUserConnected" : showFacebookInviteLink()    //Is user connects to FB, executes the provided JS function          
        });
 
    3. Now you need to call function which will provide the facebook login popup for user. User can login into facebook and then allows the application to use his/her data.
   

        FB.Connect.requireSession(); // This will give the popup to login
      
        // This will check if FB is initiated with application key and user logged in or not. On user session, it will executes the function.
        FB.ensureInit(function() {
            FB.Facebook.get_sessionState().waitUntilReady(
                    function() {
                        
            });
          
        });
 
    4. To logout from Facebook, you just need to call JS function FB.Connect.logout();

    Now you can access different functions of the FB JS library to acces any data it supports to use on your site/application having session initiated.I will show how to show invite friends popup dialog on your site/application. Call the below function on invite button/link click event.
   

       function inviteFacebookFriends() {      
        FB.ensureInit(function() {
            FB.Facebook.get_sessionState().waitUntilReady(
                function() { //on Connect succes
                        var fbml = "";
                        fbml = '<fb:fbml>\n'
                                + '<fb:request-form\n'
                                //Redirect back to this page                           
                                + ' action="'+document.location+'"\n'                           
                                + ' method="POST"\n'
                                + ' invite="true"\n'
                                + ' type="app test invite"\n'
                                + ' content="app test inviting...\n'                           
                                + '
                                + ' label=\'Join me!\' />"\n'
                                + '>\n'           
                                + ' <fb:multi-friend-selector\n'
                                + ' rows="2"\n'
                                + ' cols="4"\n'
                                + ' bypass="Cancel"\n'
                                + ' showborder="false"\n'   
                                + ' exclude_ids="excludeIds"\n'           
                                + ' actiontext="Use this form to invite your friends to connect to my site."/>\n'
                                + ' </fb:request-form>' + ' </fb:fbml>';
                      
                        var dialog = new FB.UI.FBMLPopupDialog("Invite Friends To This Site",fbml);                                      
                        dialog.setContentWidth(650);
                        //dialog.setContentHeight(450);
                        dialog.show();
            });
        });  
    }
     
Thats it! This will show the standard popup dialog for friends invitation. Basically this FBMl will be rendered by facebook js API.Now user can select any of his friends and send them invitation to join your site. Let me know if you have any queries OR problems, will try to help around.

Sunday, March 15, 2009

Telnet Client part 2 - using Apache net implementation...

I have shown Telnet client using socket programming which is my own logic.But Apache has already done this for us in their Net package which is freely available to download.So we can use that org.apache.commons.net.telnet.TelnetClient class for using telnet connection.

Its a very simple class.You can download its source and can figure out what they have done. Though i will show simple usage for it.
TelnetClient tc = new TelnetClient();
tc.connect("localhost", 23);
Then you can register a listener thread to get response from the telnet connection shown above. For full examples, check out java2s

Its nothing new, but a good implementation what we understood so far.
If you want totally command prompt like session for telnet, then you must wait for response from execution of the given command.Then only the next command will be sent over, as we do in DOS/Terminal.So for that we must have a logic which check the input stream and receives response.

Saturday, December 20, 2008

Telnet client with java...

Telnet is very important utiliy we use.We can call remote server commands and use different services running on perticular port.Mostly telnet server runs on 23,but can be differed .

Through java, if we want to make remote connection over some port then we have two different ways.

1. Use windows/linux telnet command line utility (which is same on both win and linux... :).)

OR

2. Use socket programming using java.net package.

In first way, we need to get hands on the process.We can achieve that using
Process p = Runtime.getRuntime().exec(<system command or exe path>)
But i don't think this should be used for telnet like communication,because telnet requires continuous session running on remote server and executing you commands.Sometimes it can be so that after executing several commands,you need to rollback so you can cancle all the commands.so its a continuous and sequential process most of the times.The Process class used can be out of our hands anytime if the executable crashes or if anything bad happen(Mostly..the exe crash...).


So, we have another,'Socket' way here, which connects to perticular host on given port number and try to open TCP connection with it.If the host is listening on port and connection accepted,then we can send our commands to the host.(I know, i know, that we all know sockets since our starting graduation days :) ,but let me tell guys... ).

There are two ways to make a telnet client using Sockets.
1.Make it CLI based,means which accepts every input from Command Line Interface entered by user.
2.Make it automated,which takes command list from some file or database,generates a script or list of commands and run it whole on host.

First one is quite easy,i think you all might have done that :).Just let me tell you little what to do...

1.CLI based Telnet...
Socket soc = new Socket(host,port);
DataInputStream din=new DataInputStream(soc.getInputStream());
PrintWriter dout = new PrintWriter(soc.getOutputStream(),true);

BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
See,we have taken InputStream of socket and made a PrintWriter on the OutputStreamof it to send commands.Also we have taken BufferedReader for user inputs from CL.

...
....

do
{
char[] buffer = new char[8192];
int mark = bReader.read(buffer);
StringBuffer sb = null;
for(int i=0;i<buffer.length;i++){
char c = buffer[i];
if(c!='\0'){ //To avoid null characters printed...
if(sb == null){
sb = new StringBuffer(buffer.length);
}
sb.append(c);
}
}
System.out.print((sb!=null)?sb.toString():"-- No Response --");
Command=br.readLine(); //takes commands from CL by user...
if(!Command.equals("quit"))
{
dout.println(Command);
}
}while(!Command.equals("quit")); //exit the loop if user sends 'quit'...
...


This gives you same telnet as you got in your OS, so i think its simple but good to know :)


2.Automated Telnet...

It will be almost same,except we will have a ArrayList/Array of commands in hand before we create Socket.And then change the loop onto the list to execute all the commands one after another...

int j=-1;
String[] commands = new String[5];

...
....

do
{
j++;
char[] buffer = new char[8192];
int mark = bReader.read(buffer);
StringBuffer sb = null;
for(int i=0;i<buffer.length;i++){
char c = buffer[i];
if(c!='\0'){//To avoid null characters printed...
if(sb == null){
sb = new StringBuffer(buffer.length);
}
sb.append(c);
}
}
System.out.print((sb!=null)?sb.toString():"-- No Response --");
Command = commands[j];
if(Command==null || Command.length()<0)
break;
dout.println(Command+"\n");
}while(j<commands.length);
...

So this will executes all commands in commands Array of String.


So folks,this ends our telnet socket :).Same like this we can make client or scripts for FTP automation.It helps in real time situation when you need to make some jobs for backup,export/import files on remote host etc...Waiting for you responses...

Wednesday, December 17, 2008

Snmp4J - Java library for SNMP Communication...

We all know that if we need to use more on socket programming in java then we must use native code in c++.SNMP (Simple network Management Protocol) is used for communication with the network devices.Any network device can be queried using SNMP request.Snmp4j is the library which provides you implementation to make SNMP requests.

We can query any device (Switch,PC etc...) if it has a SNMP agent running,which will handle our SNMP request and respond with the proper data.This library made it so easy for us without looking into much details of SNMP.

In basic,SNMP is used for getting information (GET requests),but sometimes it can be used to set values in the device (SET requests).Assume that every device has a list of pre-defined variables in it,which are called OID(Object IDs).These OIDs will have a specific structure (which is called MIB file,which seems like a tree structured as in registry).

OID looks like 1.3.6.1.4.1.318.1.1.1.12.3.2.1.3.1, which has a special meaning.It has a description(name) and an associated value in it.When you query particular OID (i.e 1.3.6.1....),it will give its associated value.You can set its value also (if its allowed ;)).OIDs also have communities(Public,Private etc...) which shows permissions.Mostly public community is allowed to be viewed by SNMP requests.

See the example below how to make a SNMP request,
import org.snmp4j.*;

...
...

OctetString communityName = new OctetString("public");

String ipAddressUrl = strIpAddress+"/"+161; //161 is used for SNMP Agent...

Address targetAddress = new UdpAddress(ipAddressUrl);

TransportMapping transport = new DefaultUdpTransportMapping();

Snmp snmp = new Snmp(transport);

snmp.listen();

CommunityTarget target = new CommunityTarget();

target.setAddress(targetAddress);
target.setRetries(3);
target.setTimeout(500);

PDU pdu = new PDU();
pdu.setType(PDU.GET);

OID oid = new OID("1.3.6.1.2.1.1.");
VariableBinding vb = new VariableBinding(oid);

pdu.add(vb);
...
...

snmp.send(pdu, target);
So the last line, snmp.send(pdu, target), will return the SNMP4j Response having the value for OID we set in the PDU.This is just the example of how to get any data from OID.We can set the values using SET PDU.

Monday, July 14, 2008

Remote Method call - EJB/HTTPClient/Web Service?

This is not a new thing i am talking about,but i have used this for first time. Until now i have been used to EJB for remote method invocations. I use it for some bussiness logic which is on another distributed server. And i am not ashamed of telling that i have not used Web services :(.

This was a need in my project to call a method of another application which can be on same machine or another. First i thought i need to call a EJB and its all mess because of heavy loads for a simple method call. But when i saw the implementation, i got confused how i will cuse it! But my senior told me to check using HTTPClient from apache commons.

Its very simple to call a method on servlet using HTTPClient. Check the code below. We will just use PostMethod class for parameters to be passed and execute the request. So as per the parameters,the servlet will do its work.
PostMethod postMethod = new PostMethod("http://some.blah.com");
postMethod.setParameter("some_id", "1");
postMethod.setParameter("param1", "any data");
postMethod.setParameter("param2", "any data");
...
int status = httpClient.executeMethod(postMethod); //status will be your response...
Its so simple. But though its not a call which returns something. I mean you cna see i am just passign some information to some method to invoke some processing which is independent and i don't need its response.

Tuesday, May 20, 2008

Controlling Module Dependencies in Eclipse

J2EE Module Dependencies is a critical issue in an enterprise application. You need your one web module to access some resources while prohibiting others. Similar is the case with EJB modules.

Let’s figure it out with Eclipse Web Tools Platform. I consider that you all have ability to create projects and modules in Eclipse; so skipping those steps. I have Eclipse 3.3 with WTP 2.0 M6.

I have created project with following details.

MyProject – Enterprise project

MyEJB_Module – Contains bean class

MyEJBClient_Module – Contains interfaces of EJB, VO, and BeanUtil.

MyWeb_Modules – Holds JSPs, servlets and all presentation tier stuffs.

MyJava_Module – Contains common classeslike constants, utilities.

Starting with MyProject, select properties from right click menu. In property dialog, select “J2EE Module Dependencies”. You will find all the modules. Select all as project is dependent on all modules.

Now you can configure dependency of individual module, let’s take an example of web module. In “J2EE Module Dependencies” window, you will find a radio button group which would has by default “Use EJB Client Jars” option selected. That radio button groups defines visibility of EJB jar.

As clients of any EJB should be isolated from bean classes, it is preferable not to select other options where you can define dependencies with EJB jar file. After all, EJB clients should not have any kind of dependencies with EJB jar.

Now here if I select MyEJB_ModuleClient.jar only, MyWeb_Module won’t able to access classes defined in MyJava_Module until you redefine module dependencies.

Similarity you can define dependencies with Utility project, specifically saying third party libraries. You want one module to access one jar and isolate others all you need to do is add library in main project (MyProject in my case) and then configure dependencies of other modules.

This feature takes care of dependencies on behalf of you and let you concentrate on other tasks.

Thursday, May 15, 2008

Servicemix PollingComponentSupport - stuck if lower period and higher threadPoolSize

Again i got one issue with servicemix Poller components.

We have two FilePoller components here and we kept the period to 10 minutes. Which means the instance of FilePoller will run at every 10 minutes. Now say if I have two instances, each run at 10 minutes, and 5 minutes gap between them. So it means after every five minutes, files will be picked by one of them. And the WorkManager, which is given to FilePoller as property, has threadPoolSize of 30.

All was working fine with this configuration.30 threads in pool, every five minutes any of two pullers will pick files. But now we have to change it. When we changed the period from 10 minutes to 1 minute, we got strange errors. Yes even you won't believe it. While testing concurrency we got, FileNotFound exception even though the file exists there, and many other concurrency issues. We looked into the logs and found that sometimes the load goes only on one server and the other is always idle doing nothing. Because when it comes, the first one is doing task.

Then we decided to decrease the thredPoolSize. Becasue if puller get 30 files for 30 threads from the pool, and when it comes to 31st file from the folder and if any of previous 30 threads is in the pool after it has completed its job, then it will take the file. It means, though we have pool size of 30, it may be possible that it can process more than 30 files per instance (say 32 to 38 files). So we decided to make pool size to 10.

Now after making 10 it seems to be working fine. Each one is picking almost equal numbers of files and sharing load as it should. Let’s see if more issues are coming or not.

So, key thing to be remembered is
"Keep you threadPoolSize and period on which instance will run in proportion to each other. If period is long then threads can be more but if you want to reduce the period, you must take care of pool size."

Tuesday, May 13, 2008

Java optimization and performance

No new Exception if not needed

Many of us do this when we want to throw an error. But if you are throwing exception from another catch, then don't make new exception object. Keep throwing the same exception which you caught if possible. This will be better for performance. And also in new exception usually we change the description only to reflect the perfect error cause, but other ways are there to track it.

Avoid excessive synchronization

Yah threading can be a bit complex situation sometimes in java. And we all use synchronization to avoid dead locks. But it needs a more attention then we give it. Try to make a block of code synchronized rather then making the whole method synched. The whole method will stop all other threads, waiting to go inside it. It will generate more overhead. So keep the design like we need less sync code.

Release DB and File IO

This is the most case in which we all do something wrong.
DB connections must be closed after completing your DB transactions because its a limited resource.

Also if you are using File IO, then must close file streams after completing the task.

Best way for this is, to write the releasing code in 'finally' block of the method.

Use StringBuffer/StringBuilder rather than String

We use string manipulations in our daily coding many times. And all we do is always making new String object. As most of us know, String is immutable object (which means once assigned you can't change its value), so when you assign existing String object another value, it will make new String object. And most string operation generates lot of small String objects.

If it’s possible to use StringBuffer or StringBuilder instead of String then its more more way better. Because it will be one object having all your data in it and you can get String form it when you want.

Now StringBuilder is nonSynchronized and StringBuffer is synchronized. So if you don't have threading issues and don't need Sync, then you must use StringBuilder which is included since jdk 1.5.

Later on we will talk about more points also when i remember them :)

Friday, May 9, 2008

servicemix problems: NormalizedMessage getContent,copyPropertiesAndAttachments()

Though servicemix is widely used and very nice ESB framework, it has some basic problems.The one i am talking about here is very little thing but it can be annoying if you forget this or don't know this.

While creating and sending NormalizedMessage object from any data, after doing that if you read data using NormalizedMessage.getContent() method and send the message object with exhchange to deliveryChannel, using DeliveryChannelImpl.send(MessageExchange) method, then you will get null exception in DeliveryChannelImpl class.

Yes this is true.I don't know why, but it removes content from the message object.Only the content is removed and the properties are still there.

You can read properties from it in same component as many times as you want.If you are forwarding same message to next component, properties will automatically goes.But if you read content once, you must set it again :(.

Also remember that if you need to make new MessageExchange, then you must copy all properties and attachments using TransformComponentSupport.copyPropertiesAndAttachments(outExchange,inMsg,outMsg) method.Then all your data from one message will be copied to another message.

So keep checking this if you getting null Exceptions while sending message through DeliveryChannel.