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.

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."

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.

Spring Framework problem : SqlReturnResultSet() not returned

One more problem with servicemix and spring is in DAO classes, when you make any private static class of StoreProcedure, then in its constructor you must declare SqlReturnResultSet before you declare SqlParameter.Otherwise you will not be able to find return data from StoredProcedure execution.Check the code below,
public MySp(JdbcTemplate jdbcTemplate){
super(jdbcTemplate,"sp_mysp");
declareParameter(new SqlReturnResultSet("strRs",rsMyResultSet));
declareParameter(new SqlReturnResultSet("strRs1",rsMyResultSet1));
declareParameter(new SqlParameter("myId", Types.INTEGER));
compile();
}
so keep in mind while using Spring DAO support.Must declare resultsets first.


Thursday, April 24, 2008

Servicemix Queue filled - Queue size increased

I have been using servicemix since more then 1 year.As we have seen in urlier articles that servicemix uses ActiveMQ for Message queuing. The messages sent are filled in the Queue of destined component which will be fetched later on.

When we started using Servicemix, we faced a strange problem.After running for sometimes,our application stops processing messages.When we looked in the JMS Queue, we found that after certain period the messages in the queue are not removing.So new messages can't be processed.The Queue is full and we must restart the application to get rid of this.

Then we dig into the source code of servicemix and found how queue is given size.We increased the size as per our need and the problem was solved.

Basically when message processed by the component, it will be removed from its queue.But for some reason, if message not processed or not removed from the queue then further messages will be stored in the queue and processing stops.The application seems to be running but messages are not processed.

The class org.apache.servicemix.jbi.util.BoundedLinkedQueue contains the property capacity_
Constructor of this class contains the magic which initializes the capacity of queue size.

By default it is 1024.you can change it as per your need. I mean how much messages you think will be processed after every restart.

code:
public BoundedLinkedQueue() {
this(1024);
}
public BoundedLinkedQueue(int capacity) {
if (capacity <= 0)
throw new IllegalArgumentException();
capacity_ = capacity;
putSidePutPermits_ = capacity;
head_ = new LinkedNode(null);
last_ = head_;
}
I just simply changes the 1024 to bigger number like 1024*10 etc...

Try this.may be it can solve your problem also.

And others who know about servicemix and want to share their problems and tweaks are welcome.Put your comments here i will post it.

Friday, April 11, 2008

Using Apache ServiceMix - ESB with spring


Apache ServiceMix is an open source ESB (Enterprise Service Bus) that combines the functionality of a Service Oriented Architecture (SOA) and an Event Driven Architecture (EDA) to create an agile, enterprise ESB.

Apache ServiceMix is an open source distributed ESB built from the ground up on the Java Business Integration (JBI) specification JSR 208 and released under the Apache license. The goal of JBI is to allow components and services to be integrated in a vendor independent way, allowing users and vendors to plug and play.

Features:

ServiceMix is lightweight and easily embeddable, has integrated Spring support and can be run at the edge of the network (inside a client or server), as a standalone ESB provider or as a service within another ESB. You can use ServiceMix in Java SE or a Java EE application server.

ServiceMix uses ActiveMQ to provide remoting, clustering, reliability and distributed failover.

ServiceMix is completely integrated into Apache Geronimo, which allows you to deploy JBI components and services directly into Geronimo. ServiceMix is being JBI certified as part of the Geronimo project.

Other J2EE application servers ServiceMix has been integrated with include JBoss, JOnAS with more to follow.

ServiceMix includes a complete JBI container supporting all parts of the JBI specification including:
* Normalized Message Service and Router
* JBI Management MBeans
* Ant Tasks for management and installation of components
* full support for the JBI deployment units with hot-deployment of JBI components
ServiceMix also provides a simple to use Client API for working with JBI components and services.

How to use?

JBI components can be created extending servicemix's implementation classes.This is required because only then can you will be able to use the plug-&-play component,which is our purpose to use servicemix ESB.

You can develop Binding components which can receive data through HTTP and Files.Servicemix has already provided specific classes so you can deal with http request,input folder.
HTTP - org.apache.servicemix.components.http.HttpConnector.
File - org.apache.servicemix.components.file.FilePoller
So your class will use the HTTP request/file to fetch data and will make an javax.jbi.messaging.NormalizedMessage class object.

This NormalizedMessage object will be then given to javax.jbi.messaging.MessageExchange implementation (InOnly or InOut) and MessageExchange will be then routed to the next component configured as service endpoint in application context xml file.

application context xml code:
<sm:activationSpec componentName="myfilePoller" service="foo:myfilePoller" destinationService="foo:myDrool">
<sm:component>
<bean class="test.my.file.MyFilePoller">
<property name="workManager" ref="workManager" />
<property name="file" value="C:/inbox" />
<property name="period" value="120000" />
<property name="deleteFile" value="true" />
</bean>
</sm:component>
</sm:activationSpec>

<sm:activationSpec componentName="myDrool" service="foo:myDrool">
<sm:component>
<bean class="org.apache.servicemix.components.drools.DroolsComponent">
<property name="ruleBaseResource" value="classpath:myRule1.xml" />
</bean>
</sm:component>
</sm:activationSpec>
Here MyFilePoller is the class which will poll files from 'C:/inbox' folder. And make messaging as we discussed above.'myDrool' is its destination component which is an drools component.

Drools is like dynamic routing.We just need to make rules in xml file and that xml will be loaded automtically if its configured in applicationContext file as above. Its jar must be in 'lib' dir of the server.

Below is the drools xml which declares the rule base on which the NormalizedMessage will be routed to appropriate destination component.

NormalizedMessage can contain data and properties.We can read its property in XML rule base.And based on particular property, we can route the message.

Check the xml below.

myRule1.xml:
<rule-set name="cheese rules"
xmlns="http://drools.org/rules"
xmlns:java="http://drools.org/semantics/java">
<application-data identifier="jbi">org.apache.servicemix.components.drools.JbiHelper</application-data>
<application-data identifier="context">javax.jbi.component.ComponentContext</application-data>
<application-data identifier="deliveryChannel">javax.jbi.messaging.DeliveryChannel</application-data>
<rule name="Rule for componentOne">
<parameter identifier="exchange">
<class>javax.jbi.messaging.MessageExchange</class>
</parameter>
<java:condition>"TRUE".equalsIgnoreCase(exchange.getMessage("in").getProperty("isForComponentOne").toString()) == true</java:condition>
<java:consequence>
jbi.forwardToService("http://servicemix.apache.org/demo/", "componentOne");
</java:consequence>
</rule>
<rule name="Rule for anotherComponent">
<parameter identifier="exchange">
<class>javax.jbi.messaging.MessageExchange</class>
</parameter>
<java:condition>"TRUE".equalsIgnoreCase(exchange.getMessage("in").getProperty("isForComponentOne").toString()) == false</java:condition>
<java:consequence>
jbi.forwardToService("http://servicemix.apache.org/demo/", "anotherComponent");
</java:consequence>
</rule>
</rule-set>
This will route the message to 'componentOne' if the property tested in condition is true and toward 'anotherComponent' otherwise.Both components also will be specified in applicationcontext xml file.

This is how routing does work.Now we will talk about how each component get notified of message transfered.

Every intemediate component in servicemix will create new message and Exchange,pass it to next component after finishing its processing and send notification to the previous component.

code:
getDeliveryChannel().send(newExchange);
done(exchange);
At last, we now talk about the service endpoint, which has opposite task compared to binding components.

BindingComponents takes in and creates messages, Service endpoints throw out the messages and finishes the process.

we have 3 to 4 different outbidding components here and its having some classes already provided.
File - org.apache.servicemix.components.file.FileWriter
FTP - org.apache.servicemix.components.net.FTPSender
HTTP - org.apache.servicemix.components.util.OutBinding ( i have used this becasue in http, we will jsut send data to some URL or so and then processing is finished.)
Mail/SMTP - org.apache.servicemix.components.email.MimeMailSender
This is how we can use servicemix. You can add different components as per your needs at any place in the whole flow and define the path in xml applicationContext and Rule base files.

The changes or additions afterward will require some small changes only. You need to define new properties in NormalizedMessage and based on that property you can create new RuleBase files. And using drools, create new routing path for new feature.

Its very easy to use though feels very tricky and complex in the beggining.

we Will discuss more. :)

Friday, April 4, 2008

Java Spring Framework : Multiple PropertyPlaceholderConfigurer configurtion

This is very small thing which can be very annoying while coding in spring framework. Of cource no one can directly understand the problem until he faced that.

At first, I had only one property file from which i am reading some values into spring applicationContext Xml configuration file.So when i needed to add second one for my new feature, i think it is just to add new propertyPlaceholderConfigurer bean with second prop file.

my first prop file 'default-prop.properties' is :
default-prop.custName=testing customer
default-prop.address=building1
and the bean definition in the applicationContext xml file for this is:

<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:default-prop.properties</value>
</property>
</bean>

so while adding second one, i have just added second bean for it like:
<bean id="propertyConfigurerNew"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:second-prop.properties</value>
</property>
</bean>
and in xml, prop has been read as,
<property name="customerName" value="${default-prop.custName}" />
But when i done this, i got error
"Could not resolve placeholder 'default-prop.custName' "
So i have to do some workaround and digg into spring references. And i found that we can define seperate placeHolderPrefix and suffix for each property configurer bean.

I have changed the bean definition as,
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:default-prop.properties</value>
</property>
<property name="placeholderPrefix" value="${" />
<property name="placeholderSuffix" value="}" />
</bean>

<bean id="propertyConfigurerNew"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:second-prop.properties</value>
</property>
<property name="placeholderPrefix" value="#[" />
<property name="placeholderSuffix" value="]" />
</bean>
it means, for first prop bean, we will use ${default-prop.custName} and for second bean we will use #[second-prop.secondName]

And voila! it solved my problem...

You can also use
<property name="ignoreUnresolvablePlaceholders" value="true" />
for each PropertyPlaceholderConfigurer bean defined. But, i have used the prefix-suffix one solution.
And my problem is resolved.

Give your comments on this problem and solution.