1
votes

Despite the fact messagedriven bean is based on asynchronous logic, I have the following scenario:

  1. 2 realms containing user credentials (jdbc and ldap)
  2. When user put Username and Password at form, it tries to autenticate in both realms (jdbc and ldap)
  3. For each realm attempt to login, I send a message with JMS to log it

My problem lies at onMessage(Message message) overrided method.

Considering Java-Pseudocode below for a JMS Message Bean:

public void onMessage(Message message){
    String username = (cast message to Map and get username);
    Login login = (Login)loginDAO.filter( queryByUsername, username );
    if( login == null ){
        Creates a new entry at database for 'username'
    }else{
        Uses 'username' already created
    }
}

Now my issue scenario:

  1. I put my username and password in the form and press Login
  2. attempt to login at JDBC and fires a JMS to log it
  3. attempt to login at LDAP and fires a JMS to log it
  4. onMessage receives 2 messages (item 2 and 3) almost at sametime
  5. Message 1 creates a new user since it doesnt exist at database
  6. Message 2 also creates a new user with same username

I need that Message 2 uses the created user (else logic) on Message 1 (if logic), but I think that it(message 2) is so fast that entry is not persisted yet at DB and both message are catched at "if logic".

Please advice if my topic is confuse and not appropriated.

[EDIT] Until now what I've got:

There is a POOL of MessageDriven Beans (MDB) in the server, for 2 messages arriving you will get 2 MDBs running at the same time, so you will persist the same information 2 times.

I used an attribute called maxSession in my Annotation Message Driven Bean

@ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")

Now I have only one MDB at the pool and I put a SYNCHRONIZED at the method responsible for checking all the logic for the 'username' login audit.

[EDIT 2] As per observed by Nicholas below:

Removed pool restriction and I created a static method for database check (check if username exists or needs to be created and persisted).

Static because it needs to be shared with all instances of the MDB and also Synchronized to avoid duplicating entries at DB.

Thank you

1
Does your database not have a PK for the table that stores the user details? Surely the second insert will throw an exception. - ramp
yes it has. I'm using JPA so hibernate increments ID in the persist entitymanager - Solano

1 Answers

1
votes

Without knowing what this code is actually supposed to be doing, it still seems that the MDB is wrong place to implement synchronization. Presumably, you will have a finite number of users and you will be processing multiple messages per user. By restricting the MDB pool to one instance, you are seriosuly limiting the throughput on the MDB processor.

Rather than trying to synchronize in the MDB, I suggest you look at implementing the synchronization in the username persistence mechanism, or as you described it in your code:

Creates a new entry at database for 'username'

That way, multiple messages can be processed concurrently, but they will briefly block while fortune decides which thread gets to save the username, (one will save it, then get it, the others will wait and then get it). After that you won't ever block for a single username more than once and you can run a full pool of MDBs.