Tuesday, June 12, 2012

JMS Queue in a Clustered Environment

Using JMS queues is quite simple once set up correctly.

But the simpleness immediately disappears when working in a clustered environment, whichever technology you are using; often you'll get NameNotFoundException or JMSException: Connection not found while trying to contact the JMS server.

The reasons can be many, but most of the time the problem is in the JNDI Lookup procedure: in a clustered environment, is important to preserve uniqueness of server names, to avoid the needs of complex tricks and the appearance of weird and mysterious errors.

A Technote from IBM explains that, in a Websphere clustered environment
"...in which 2 nodes have Application Servers with the same name, an attempt to lookup an EJB in the name space during an EJB invocation finds the wrong server.
[...]
The solution for this problem is to have different server names for the servers for 2 different nodes."

This happens because both Application Servers on different nodes have same name (server1 in the example), and trying to lookup server1 on ejb node from application node will instead return the server1 of application node, the local one.

The same thing happens on Weblogic, as they states in JMS Admin documentation (page 55):

"Note: JMS clients depend on unique WebLogic Server names to successfully access a cluster — even when WebLogic Servers reside in different domains. Therefore, make sure that all WebLogic Servers that JMS clients contact have unique server names."

Different server names, correct Lookups. That's all folks.

Hope that helps ;)

Monday, June 4, 2012

Struts2 XML VALIDATION

Struts 2 framework allows powerful and easy validation through Java, XML or Annotations.
The first way (override of Validate() method) should be avoided.
Both XML and Annotations are good ways to go, but as usual they're poorly documented / exampled.
Let's take a look at XML Validation:


STANDARD XML VALIDATION

Scenario:
You have a JSP that posts a form with new data (let's say one record about a person) to be inserted, to an Action named InsertOneRowAction.java.
Data posted are: Name and Birthday (KISS paradigm ftw...).
Fields in JSP page are named person.name and person.birthday (getters of Person.java value object).
Both fields are mandatory, and Birthday must be a valid date between 1990 and 2000.

Solution:
Create a file with the name of the action and append "-Validation.xml" at the end, in the same package of the action.
We will see then:
com.andrealigios.struts2validation.presentation.action.InsertOneRowAction.java
com.andrealigios.struts2validation.presentation.action.InsertOneRowAction-Validation.xml


Open XML validation file and write the desired rules in there, in this case:

  <field name="person.name">
      <field-validator type="requiredstring">
          <message><![CDATA[ Name is mandatory ]]></message>
      </field-validator>
  </field>
  <field name="person.birthday">
        <field-validator type="required">
            <message><![CDATA[ Birthday is mandatory ]]></message>
        </field-validator>
        <field-validator type="date">
            <param name="min">01/01/1990</param>
            <param name="max">01/01/2000</param>
            <message><![CDATA[ Birthday must be a valid date between ${min} and ${max} ]]></message>
        </field-validator>
    </field>



Now put the tag <fielderrors/> into your JSP.
Done!

Every time your data posted won't match the validation criteria, the Validation Interceptor will redirect your post to the source JSP page, showing the error messages and preventing wrong / incomplete data to reach the action's setters.


DYNAMIC XML VALIDATION - FIELDEXPRESSION VALIDATOR

Let's dig a bit deeper: we need min and max Date parameters to be dynamic, for example read from a database or a configuration file.
We need to create a getter for each parameter, that does its business inside, and returns the desired java.util.Date.
We can put the getter into the Action, or into Actions that are extended by ours (let's say BaseAction). Remind to preserve getters's visibility ;)

 
public Date getMinDateDynamicallyRead(){
 // Do business
 return minDate; 
}

public Date getMaxDateDynamicallyRead(){
 // Do business
 return maxDate; 
}


Now, let's modify XML Validation file as follows:

  <field name="person.birthday">
        <field-validator type="required">
            <message><![CDATA[ Birthday is mandatory ]]></message>
        </field-validator>
        <field-validator type="date">
            <message><![CDATA[ Birthday must be a valid date ]]></message>
        </field-validator>
      <field-validator type="fieldexpression">
        <param name="expression"> 
          <![CDATA[ person.birthday==null || (person.birthday >= minDateDynamicallyRead && person.birthday <=  maxDateDynamicallyRead) ]]>
        </param> 
        <message><![CDATA[ Birthday must be between ${minDateDynamicallyRead} and ${maxDateDynamicallyRead} ]]></message>
         </field-validator>
    </field>



The person.birthday == null part is necessary to avoid redundancy of messages. If date is not provided, then the "required" validator must raise the error message, but there's no need to show that date is not inside our desired interval too...

Note that you can chain multiple "fieldexpression" validators for a single field, performing different controls and showing different messages.


MULTIPLE ROWS XML VALIDATION - VISITOR VALIDATOR

Now let's understand the most powerful, less documented feature of Struts 2 Validation : VISITOR validation.

Scenario:
We are on a different JSP page, that shows us a list of persons, and allows us to perform multiple changes to their Names and Birthdays, and to save 'em all with one click on the UPDATE button.
The main object into the JSP is PersonsTable.java (exposed through a getter from the Action), that exposes a list of Person.java objects, cycled within an iterator in the JSP:


public List<Person> getPersonsFromDatabase(){ 
    return savedPersons; 
}

The JSP UPDATE button posts to an Action named UpdateMultipleRowsAction.java
(We obviously can't validate the persons in the previous way, because we can't (and definitely don't want to) write a huge, static XML file specifying row indexes ;)

Struts2 allows us to resolve the problem like follows:

Create the usual XML Validation file in action's package, beside the action:
com.andrealigios.struts2validation.presentation.action.UpdateMultipleRowsAction.java
com.andrealigios.struts2validation.presentation.action.UpdateMultipleRowsAction-Validation.xml

inside the xml file, let's write:

<validators>
  <field name="personsTable.personsFromDatabase">
      <field-validator type="visitor">
          <message></message>
      </field-validator>
  </field>
</validators>


This command will tell Struts to perform, for EVERY single row, the validation using the validation rules of the object listed (in this case, Person.java).
The real validation must be written into an xml file UNDER THE OBJECT PACKAGE (NOT the Actions package), with a name composed by the Object class concatenated to "-Validation.xml".

For example:
com.andrealigios.struts2validation.valueobject.Person.java
com.andrealigios.struts2validation.valueobject.Person-Validation.xml

Inside Person-Validation.xml, we can put the same rules used in previous examples, pointing to the name of the field (name of the getters of Person.java, in this case "name" or "birthday", without "person" or other stuff before), as follows:


  <field name="name">
      <field-validator type="requiredstring">
          <message><![CDATA[ Name is mandatory ]]></message>
      </field-validator>
  </field>
  <field name="birthday">
        <field-validator type="required">
            <message><![CDATA[ Birthday is mandatory ]]></message>
        </field-validator>
        <field-validator type="date">
            <param name="min">01/01/1990</param>
            <param name="max">01/01/2000</param>
            <message><![CDATA[ Birthday must be a valid date between ${min} and ${max} ]]></message>
        </field-validator>
    </field>


Enjoy, forgive my Engrish and... comment!! ;)