Tuesday, October 18, 2011

SingleThreadModel : why you should not implement it and what happens if you do

According to the Servlet specifications, the SingleThreadModel interface is deprecated since the 2.4 version of the specs. The reason why it has been deprecated is that it cannot actually guarantee thread-safety, as its name suggests. But do you know what would the consequences be if you still have a servlet implement SingleThreadModel?

The side-effects of having a servlet implement SingleThreadModel are vendor-specific. Having worked with some legacy code deployed on a Tomcat 4.x container which contains a servlet that implements SingleThreadModel, I've noticed the following behavior : the container can processed a maximum of 20 simultaneous POST requests.

Explanations

Since true thread-safety cannot be achieved by implementing SingleThreadModel, each servlet container will have 2 possibilities for treating SingleThreadModel type servlets :

  • the container manages a servlet pool (2 simultaneous requests to a same servlet will actually be handled by 2 distinct instances of the requested servlet).
  • the container synchronizes the service( ) method of the requested servlet
Use-case : SingleThreadModel servlet deployed on Tomcat
 
Here's the code for the servlet we'll deployed onto any version of Tomcat for our test purpose :


public class TestServlet extends HttpServlet implements SingleThreadModel {
 private static int requestCounter = 0;
 
 @Override
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  
  doGet(req, resp);
 }
 
 @Override
 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
   throws ServletException, IOException {
  
  try {
   System.out.println("Start processing request with servlet " 
                        + instance : " + this + "[CPT : " + ++requestCounter + "]");
   Thread.sleep(1000000); // simulate a uber long request
  } catch (InterruptedException e) {
   e.printStackTrace();
  }
 }
}

How to run the test?

Simply send 21 POST requests to the servlet and you'll see that the 21st request and the following ones aren't not processed by the container :



Where is this limit of 20 servlet instances configured?





Conclusion


Having a servlet implement SingleThreadModel is definitely a conception flaw that could lead to performance breakdown in the best case scenario, and to a deadlock in the worse case scenario.



Sunday, August 21, 2011

Intalio BPMS : replacing the Derby in-memory DB by MySQL

By default, Intalio BPMS Enterprise Edition is configured to run against a Derby in-memory DB. This DB configuration is pretty handy and make Intalio an out of the box tool for deploying and executing business processes. Nevertheless, as soon as you'll be considering integrating Intalio to a production environment, you'll may also consider having Intalio run against a more robust RDBMS for different reasons : crash recovery facilities, backup & restore procedures, and so on. Most of the most popular RDMBS are supported by Intalio BPMS but the Community Edition only supports MySQL. 

This post describes the procedure to follow to have Intalio BPMS run against a MySQL DB.

1° Tool versions

Here are the tools and their respective version the following procedure is intended to :
  • intalio-bpms-6.0.3.022
  • mysql-5.5.15-win32 (Zip archive)
  • Windows Vista 32bits
2° Setting up MySQL and creating a database for Intalio
  • First, unzip the MySQL archive and let's refer to this directory as MYSQL_HOME
  • Open a CMD console and go to the %MYSQL_HOME%/bin directory. Then execute : mysqld --console to startup the DB server
  • By default, the MySQL root user does not have any password associated. You can defined its password by executing : mysqladmin -u root password PASSWORD (PASSWORD's value is up to you, of course)
  • Let's create a DB user for the Intalio server. First, connect to MySQL as user "root" : mysql -u root -p (the -p option will make the console ask you the password). Then execute the following command : mysql > CREATE USER 'intalio'@'localhost' IDENTIFIED BY PASSWORD; (PASSWORD's value corresponds to the password assigned to the user 'intalio' and is up to you ) (don't forget the semicolon to have the MySQL prompt execute your command)
  • Let's create a database for Intalio (I called it "intaliodb" but you can choose another name for yours). For this command too, you'll have to connect to the MySQL server as user "root" : mysql > create database intaliodb; (after having executed this command, you can check the "intaliodb" database does exist by executing this command : show databases;)
  • Once the "intaliodb" has been created, you'll have to grant some permissions to the user "intalio" so that it will be able to create new tables, rows, and so on. Here's the command to execute, once you're connected as user "root" : mysql > grant CREATE,INSERT,DELETE,UPDATE,SELECT on intaliodb.* to intalio@localhost;
3° Configuring Intalio server
  • At %INTALIO_HOME%/databases/MySQL, you'll find a SQL script named BPMS.sql. Executing this script on the "intaliodb" database will create the tables and indexes required by Intalio BPMS. Beware !!! This script contains the "type" keyword that's deprecated since MySQL 4.x. To execute this script on our MySQL 5.x server, we'll have to manually replace the "type" keyword by "engine" (basically, you only need to replace all the "type=innodb" and "type = innodb" in the BPMS.sql script by "engine=innodb"). Then, simply execute the script : (from a CMD console) mysql -u root -p intaliodb < PATH_TO_SCRIPT_FILE
  • The last required step to configure the Intalio server is telling the Intalio server which JDBC driver it shoud use, and which database it should connect to. To achieve this, just replace the content of the %INTALIO_HOME%/conf/resources.properties file by the content of the %INTALIO_HOME%/databases/MySQL/tomcat-5-resources.properties file. Then, you'll need to customize some parameters to your own configuration. If you followed this procedure, here's how you properties file should look like : 


4° Redeploying existing processes 
  • Now that we've replaced the default Derby database server by MySQL, all we need to do is redeploying the existing processes so that their associated info are stored in the MySQL server. To do that, start your Intalio server and then delete all the files with the .deployed extension in the %INTALIO_HOME%/var/deploy directory. The deleted file should be recreated after a few seconds, which is the time the Intalio server needs to hot-redeploy the processes.
5° Test

In order to check that your new Intalio configuration runs smoothly, you could run some of your existing processes (preferably, some with tasks or notifications) and then, check what is actually stored in the database. 

I'm personally using either SqlWave or HeidiSQL which are both great MySQL GUI clients when I need to perform some sort of monitoring work on the database used by my Intalio processes. Feel free to take a look at the tables whose name begins with "tempo_", they hold all the info related to your processes (tasks, notification, task status, assigned user, and so on) : 


    Sunday, July 10, 2011

    EJB 3 example - Exposing a stateless session beans as a web service (JBoss AS6)

    In this post, we'll see how to expose an EJB3 stateless session bean as a web service using annotations (= Top-down method given that the starting point is code implementation), within JBoss AS 6. For those who are already familiar with JAX-WS annotations, the implementation part will be straightforward. But the tricky part could reside in how to retrieve its WSDL in order to invoke it : this part depends on the server in use and may even be vendor-specific. If you deploy a web service on a Tomcat server, for instance, it is possible to specify in the server.xml file that you want to publish a list of all the available web services from a given application context...

    You'll see below that retrieving the WSDL from a web service deployed on JBoss AS 6 is even simpler.

    1° Implementing the web service

    One important thing you shouldn't forget is that, as defined in the EJB 3 specifications, only stateless session beans can be exposed as web services. Below, you'll see the 2 ways JAX-WS specifications allow you to follow in order to implement a stateless session bean as a web service : with or without defining an interface.

    A. Without defining a service interface

    package beans;
    
    import java.math.BigDecimal;
    
    import javax.ejb.Stateless;
    import javax.jws.WebService;
    
    @Stateless
    @WebService(serviceName = "CalcService", portName = "CalcPort")
    public class CalculatorBean {
     
     public Double add(Double operand1, Double operand2){
      BigDecimal op1 = new BigDecimal(operand1.toString());
      BigDecimal op2 = new BigDecimal(operand2.toString());
      
      return op1.add(op2).doubleValue();
     }
    }

    B With a service interface
    package beans;
    
    import java.util.Date;
    
    import javax.jws.WebService;
    
    @WebService
    public interface Clock {
     
     public Date getTime();
    }
    
    
    package beans;
    
    import java.util.Date;
    
    import javax.ejb.Stateless;
    import javax.jws.WebService;
    
    @Stateless
    @WebService(serviceName="G-Shock", portName="G-Shock-Port", endpointInterface="beans.Clock")
    public class ClockBean implements Clock{
    
     @Override
     public Date getTime() {
      return new Date();
     }
    
    }
    
     

    To test these classes, simply create an EJB project with Eclipse (FYI, I'm using Eclipse Helios). Create a source folder named "src" within this project. Then create a package named "beans". Paste the 2 classes and the interface in the "beans package" and deploy the whole project on the JBoss AS server.

    2° Accessing the published WSDL

    Once both the services are deployed, go to the administration page of your JBoss AS server (since I'm working locally using the 8080 port, mine is located at http://localhost:8080) :


    Then, click on "JBoss Web Services Console". This link will bring you into the JBossWS page. Then, click on  "View a list of deployed services" This will bring you to a page where you'll see a list of available web services : 


    From this page, you can click on the "Endpoint Address" of each service, which will bring you to the corresponding WSDL.

    VoilĂ , you're go to go with your first EJB 3 compliant web service.

    Sunday, June 5, 2011

    EJB 3 example - How to use Timer service (JBoss AS 6)

    Through this post, I wanna show you how easy it is to use the timer service provided by EJB 3 compliant application server. The timer service is a very convenient feature that helps you schedule tasks that must be ran once or repeatedly. Besides, timers created with the timer service are persisted so that they're kept running when the server is restarted (useful for crash-recovery). As stated in the title, I use JBoss AS 6 to deploy my example but you could deploy yours on any other EJB 3 compliant application server.

    Description of my example

    In my example, I've implemented a stateless session bean that manage user subscriptions to a website. At each subscription, I'll start a timer that will check, every once in a while, whether the subscribed user is still active (for that purpose, every user record in my database will contain a column that contains the last connection date).

    Java EE timer service : annotation or deployment descriptor?

    As almost every service available in Java EE, you could configure timer service either with annotations or with the deployment descriptor. But you'll typically configure it with annotation because configuring it via the description descriptor will make you loose some flexibility : using annotation, you'll be able to start, cancel, define timer delay, and so on, from within your code.

    Where to use timer service?

    As for EJB 3 specifications, timer can be created only for stateless session bean and for message-driven bean.

    How to use timer service ?

    1° In order to create a timer, you'll need to get hold of an instance of TimerService. To do so, there are 3 possibilities : 
    • through dependency injection :  @resource private TimerService timerService;
    • through JNDI lookup
    • through EJBContext : @resource private EJBContext context; context.getTimerService( );
    2° Specify the method within your bean, that will be executed by the timer. To do so, there are 2 possibilities
    • Implement a method with the following signature : public/protected void methodName (Timer timer) and annotate it with @Timeout.
    • Have your bean implement the TimedObject interface. You'll  then have to implement the public void ejbTimeout(Timer timer) method
    3° Finally, you'll have to create a timer from within the bean. To do so, you can call methods such as createTimer(...) and createCalendarTimer(...) on the TimerServiceInstance.

    Code example
    package beans.userManagement;
    
    import java.io.Serializable;
    import java.math.BigInteger;
    import java.security.SecureRandom;
    import java.util.Date;
    
    import javax.annotation.Resource;
    import javax.ejb.EJB;
    import javax.ejb.Stateless;
    import javax.ejb.Timeout;
    import javax.ejb.Timer;
    import javax.ejb.TimerService;
    import javax.interceptor.AroundInvoke;
    import javax.interceptor.InvocationContext;
    
    import tools.StringManager;
    import beans.dao.UserDao;
    import beans.emailManagement.EmailManagement;
    import dto.User;
    import exceptions.EmailException;
    import exceptions.UserManagementException;
    
    /**
     * Session Bean implementation class UserSubscriptionManagementBean
     */
    @Stateless
    public class UserSubscriptionManagementBean implements UserSubscriptionManagementLocal, UserSubscriptionManagementRemote{
        private static final long NB_DAYS_BEFORE_REMOVAL = 30L;
        private static final long NB_DAYS_BEFORE_WARNING = 15L;
        private static final long MAXIMUM_INACTIVE_PERIOD_BEFORE_REMOVAL = 1000L * 3600L * 24L * NB_DAYS_BEFORE_REMOVAL; // maximum inactivity period = 30 days 
        private static final long MAXIMUM_INACTIVE_PERIOD_BEFORE_WARNING = 1000L * 3600L * 24L * NB_DAYS_BEFORE_WARNING;
    
        @EJB
        private UserDao userDao;
        @EJB
        private EmailManagement emailManager;
        @Resource
        private TimerService timerService;
    
        private User user;
    
        /**
         * Default constructor. 
         */
        public UserSubscriptionManagementBean() {}
    
        @Override
        public void subscribe(String email, String nickname, String password, 
                String firstName, String lastName, Date birthdate, Date subscriptionDate) throws UserManagementException {
    
            // insert new User in database
            ...
            
            userDao.insert(user);
            // starting a timer to cleanup inactive user / send warning
            createTimers();
        }
    
        private void createTimers(){
            timerService.createTimer(MAXIMUM_INACTIVE_PERIOD_BEFORE_WARNING, user.getEmail());
            timerService.createTimer(MAXIMUM_INACTIVE_PERIOD_BEFORE_REMOVAL, user);
        }
    
        @Timeout
        public void cleanupInactiveUsers(Timer timer){
            Serializable info = timer.getInfo();
    
            if(info != null){
                if(info instanceof User){ // deleting inactive user
                    User userToCheck = userDao.find(((User)info).getEmail());
    
                    if(userToCheck == null){
                        return;
                    }
                    
                    Long inactivityPeriod = System.currentTimeMillis() - userToCheck.getLastConnectionDate().getTime();
    
                    if(inactivityPeriod >= MAXIMUM_INACTIVE_PERIOD_BEFORE_REMOVAL){
                        userDao.delete(userToCheck);
                        StringBuilder object = new StringBuilder("Automatic unsubscription");
                        StringBuilder message = new StringBuilder();
                        message.append("Your Crowd Freighting account has been deleted due to " + NB_DAYS_BEFORE_REMOVAL + " days inactivity");
                        message.append("\n\nKind regards, \nThe Crowd Freighting Crew.");
    
                        try {
                            emailManager.sendEmail(new String[]{userToCheck.getEmail()}, 
                                                   null, 
                                                   null, 
                                                   object.toString(), 
                                                   message.toString());                    
                        } catch (EmailException e) {
                            e.printStackTrace();
                        }
                    }else{
                        timerService.createTimer(MAXIMUM_INACTIVE_PERIOD_BEFORE_REMOVAL - inactivityPeriod, userToCheck);
                    }
                }else if(info instanceof String){ // send warning to user
                    User userToCheck = userDao.find((String) info);
                    Long inactivityPeriod = System.currentTimeMillis() - userToCheck.getLastConnectionDate().getTime();
    
                    if(inactivityPeriod >= MAXIMUM_INACTIVE_PERIOD_BEFORE_WARNING){
                        StringBuilder object = new StringBuilder("Subscription warning");
                        StringBuilder message = new StringBuilder();
                        message.append("Your Crowd Freighting account has been inactive for " + NB_DAYS_BEFORE_WARNING + " days.");
                        message.append("\nIt will be removed from our database when it reached " + NB_DAYS_BEFORE_REMOVAL + " days of inactvity");
                        message.append("\n\nKind regards, \nThe Crowd Freighting Crew.");
                        
                        try {
                            emailManager.sendEmail(new String[]{userToCheck.getEmail()}, 
                                                   null, 
                                                   null, 
                                                   object.toString(), 
                                                   message.toString());                    
                        } catch (EmailException e) {
                            e.printStackTrace();
                        }
                    }else{
                        timerService.createTimer(MAXIMUM_INACTIVE_PERIOD_BEFORE_REMOVAL - inactivityPeriod, userToCheck);
                    }
                }
            }
        }
    } 

    Troubeshooting for JBoss AS 6


    When using timer service with JBoss AS 6, you may run into the following exception : 

    21:40:29,665 WARN  [com.arjuna.ats.arjuna] ARJUNA-12140 Adding multiple last resources is disallowed.
    Current resource is com.arjuna.ats.internal.arjuna.abstractrecords.LastResourceRecord@1bc46c
    21:40:29,665 WARN  [org.hibernate.util.JDBCExceptionReporter] SQL Error: 0, SQLState: null
    21:40:29,665 ERROR [org.hibernate.util.JDBCExceptionReporter] Could not enlist in transaction
    on entering meta-aware object!; - nested throwable:
    (javax.transaction.SystemException: java.lang.Throwable: Unabled to enlist resource,
    see the previous warnings. 
    ....

    The explanation is that since JBoss AS 6, the server default behavior seems to allow only one datasource at a time. The thing is timer service already use a datasource to persist timer ... To solve this issue, you'll need to edit the %JBOSS_HOME%\server\%YOUR_SERVER_PROFILE%\deploy\transaction-jboss-beans.xml file and add the following property : 

    <property name="allowMultipleLastResources">true</property>

    in the following bean : 

    <bean name="CoreEnvironmentBean" class="com.arjuna.ats.arjuna.common.CoreEnvironmentBean">

    Sunday, May 29, 2011

    Intalio : example on how to manage deadline with tasks

    In this post, I'll define a simple process to illustrate how to check whether a task deadline is reached. Below, you'll find a link to download my process project as well as the detailed process definition step by step.


    Process definition (step by step)
    1. In the Intalio Designer, create a new project and name it "DeadlineManagement"
    2. Create a new "Business Process Diagram" and name it "DeadlineManagement.bpm"
    3. Add a pool to the diagram and name it "User"
    4. Set the "User" pool as non executable
    5. Add a task to the "User" pool and name it "Start process"
    6. Add a second pool and name it "Process tasks" (make sure this one is set as executable, which is the default configuration)
    7. Add a message start event to the "Process tasks" pool
    8. Drag the outgoing arrow from the "Start process" task (from the "User" pool) to the message start event
    9. In the project explorer, add a new directory and name it "messages".
    10. In the "messages" directory, create a new XML schema and name it "ProcessInput.xsd" (this schema defines the structure of the message that executes the process)
    11. In the XML schema, add a complex type and name it "InputMessage". In this complex type, add 3 elements :
      •  a string type element named "initialUser"
      • a string type element named "deadline"
      • a string type element named "reminderUser"
    12. Drag the complex type onto the arrow that links the "Start process" task and the message start event. Then choose the "Set schema type InputMessage as the content of the message"
    13. From the message start event, drag the outgoing arrow to the right and create a new task. Then, name this task "Create user task"
    14. Back in the project explorer view, create a new directory and name it "Forms"
    15. In the "Forms" directory, create a new Ajax form and name it "UserForm"
    16. Drag the form into the "User" pool and choose the "Create and complete" option
    17. From the "Create user task", drag the outgoing arrow to the right and create a new task named "Complete user task"
    18. From the "UserForm-create" node, drag both the outgoing and ingoing arrows to the "Create user task" task
    19. From the "Complete user task" task, drag both the outgoing and ingoing arrows to the "UserForm-complete" node
    20. Set the focus on the "Create user task" task and open the mapper view
    21. Map the "initialUser" from the input message to the "userOwner" task metadata. Then, map the "deadline" from the input message to the "until" task metadata
    22. From the "Complete user task" task, drag the outgoing arrow to the right and create a Gateway with type "Exclusive data-based gateway
    23. From the gateway, drag the outgoing arrow to the right; create a new task and name it "Process task without expiration"
    24. From the gateway, drag another outgoing arrow to the right; create a new task and name it "Clone task with high priority"
    25. Right click on the arrow that binds the gateway and the "Process task without expiration" task. Then choose "Condition type --> default" 
    26. Set the focus on the gateway and open the mapper view : 
      • add an "=" operator
      • Create a static argument with the value "DeadlineReached" and set it as input to the "=" operator
      • Set the "status" element from the "userFormNotifyTaskCompletionRequestMsg.root" node as the second argument of the "=" operator
      • map the result of the "=" operator to the "condition" node
    27. At this point, from the "Clone task with high priority" task, you could manage task expiration as you wish. In this example, I've chosen to recreate the initial task and assign it to another user, with another priority and a deadline = 31/12/2011 22:00  (this illustrates how you can reassign a task to a manager, in case it hasn't been completed by one of its underlings, for instance)
    Running the process

    Once the process is deploy, you can run it from the BPMS console. The input message we've defined through the XML schema will result in the user having to introduce the following info : 

    Now, let's log in the UI-FW console as the "examples/msmith" user : 


    Then, let's wait until 22:20. The task will disappear from the list of the "examples/msmith" user. Once logged in as "examples/ewilliams", we can see that the cloned task has been created : 


    Download the sample project

      Wednesday, May 4, 2011

      Configuring JBoss mail service to use Gmail as SMTP server

      In this post, I'll show how to configure the JBoss mail service to use Gmail as an SMTP server, so that you'll be able to send emails using a valid Gmail account, from within an application that has been deployed in JBoss. 

      1° Environment / Prerequisites

      • As in the other posts, I am running JBoss AS 6
      • Any valid Gmail account
      2° Mail service configuration


      In the deploy directory of your JBoss server, you'll find a file name mail-service.xml (note that this file only exists in the deploy directory of the following server profiles : ALL, DEFAULT and standard). Simply edit this file as shown below :

      
      
       
       
       
      
       
        java:/GMail
      
        
        someuser@gmail.com
      
        
        myPassword
      
        
         
          
          
          
          
         
        
        jboss:service=Naming
       
      
      
      3° Sending mail : example

      On the personal project I am currently working at, mails are sent from a business method within a stateless session bean. Here's the code excerpt that does send the mail : 


      Context initCtx;
        try {
         initCtx = new InitialContext();
         Session session = (Session) initCtx.lookup("java:/GMail");
         Message message = new MimeMessage(session);
         
         InternetAddress to[] = new InternetAddress[1];
         to[0] = new InternetAddress("destination@gmail.com");  
         message.setRecipients(Message.RecipientType.TO, to);
         
         message.setSubject("How to send a mail with GMAIL from JBoss AS");
         message.setContent("Hello world", "text/plain");
         Transport.send(message);
        } catch (NamingException e) {
         e.printStackTrace();
        } catch (AddressException e) {
         e.printStackTrace();
        } catch (MessagingException e) {
         e.printStackTrace();
        }
      
      Now, let's take a look at the recipient mailbox : 


      Wednesday, April 27, 2011

      Intalio : how to dynamically set task metadata

      In this post, I'll explain how you can dynamically set values to the task metadata. By doing so, you'll be able to have absolute control of your tasks on runtime : dynamically assigning a task to one/several users, one/several user groups, defining a deadline, etc, would be a piece of cake.

      To illustrate my point, let's define a real simple and basic process (its design shouldn't be a problem for you at all but if you're not familiar with the Intalio designer yet, just leave a comment and I'll send the whole sample project to you) :

      1° Sample process


      Two important things here :
      • for this post purpose, I didn't waste my time creating an elaborate AjaxForm for the task. Actually, I've simply created an empty form. So, don't waste yours neither if you're only trying to replicate the process.
      • as you can see on the screenshot, there's a warning mark on the form. The reason is that I did not assign the task to any user or group, given I am going to show how you can dynamically assign a task. For those who absolutely can't bear to have warnings in their project, just go ahead and assign a static user/group, the result will be the same.

      2° Setting value on task metadata

      Task metadata can have a value dynamically set through the mapper : set the focus on the node that is creating the task (in the example process, that is the red surrounded node) and open the Mapper view :


      Then, expand the "createTaskMsg" root element and you'll see all the task metadata to which you can dynamically set a value. In this example, I've assigned the task to 2 users : examples/ewilliams and examples/msmith.

      Note that in my example, though the users are set through the mapper, it is rather static because I used a static value. But this can be done dynamically because the value that is set to the userOwners element can be retrieved from a web service, a DB datasource, a message that is defined with an XSD, ...



      3° Running the example

      Executing this process will yield the following result in the UI-FW console :

      Logged in as "intalio/admin":



      Logged in as "examples/msmith":



      Logged in as "examples/ewilliams":


      By the way, in this example, you've probably noticed how convenient it is to have a column in the task list showing the users to whom a task has been assigned ... This feature could be very useful once you need to implement hierarchies among users and user groups.


      4° Adding an actual dynamic metadata


      Now that we've seen how values can be set to task metadata, let's add an actual dynamic metadata. In the process view, we'll map the String element that comes as input to the process when it is executed to the task deadline element : 



      Now, let's start the same process from the BPMS console and as input, we'll provide the following value : 2011-12-31T11:00:00 (correct format for datetime type is yyyy-MM-ddThh:mm:ss)



      As a result, the "examples/ewilliams" and "examples/msmith" users will have a task that must be completed by 11:00 December 31 2011.