Tuesday, December 29, 2009

Credit card validator in JSF

If you have a JSF page with credit card information you might want to validate the credit card number the user is entering. Different credit card companies (VISA,Master & Amex) have credit card numbers that follow different validation rules. All major credit cards will satisfy a Cyclic Redundancy Check (CRC) called Luhn Algorithm.

Luhn Algorithm

Step1: Sum all odd digits of the credit card number
Step2: Take each even digit multiply it by 2 if the result is greater than 9 subtract 9 from it then add it to the Sum of Step1
Step3: If sum is divisible by 10 then CRC passed else failed

To implement this lets do the following
1.In your JSP page which has the credit card form add the validator to the the card number input text field


<h:inputText label="Credit Card Number:"
id="inpCCnumber" required="true"
value="#{backing_ccbean.cardNumber}">
<f:validator validatorId="CreditCardValidator"/>
</h:inputText>




As you can see the custom credit card validator is called CreditCardValidator. The value is stored in the backing_ccbean. Assume there is a drop down list from which the user selects the card type(Visa,Master or Amex) and this value is stored in the same backing bean backing_ccbean in the attribute cardType, however this value will be set to the model object only after the validation phase so we need to directly bind to the component



<h:selectOneListBox label="Credit card type" value="#{backing_ccbean.cardType}"
binding="#{backing_requestscope.cardTypeChoice}">
<f:selectItem itemValue="1" itemLabel="Visa" />
<f:selectItem itemValue="2" itemLabel="Master Card" />
<f:selectItem itemValue="3" itemLabel="American Express" />
</h:selectOneListBox>




backing_requestscope.cardTypeChoice maps to a javax.faces.component.html.HtmlSelectOneListBox this way we get the users selection in the validation phase of the JSF life cycle.

2. The next step would be to define CreditCardValidator in faces-config.xml. Add the following XML element to your faces-config


<validator>
<validator-id>CreditCardValidator</validator-id>
<validator-class>validators.MyCreditCardValidator</validator-class>
</validator>


The XML element is simple there is an ID and a Class we have called it MyCreditCardValidator.

3. Now let us write the java class MyCreditCardValidator in the package validators





package validators;

public class MyCreditCardValidator implements javax.faces.validator.Validator{


public void validate(FacesContext ctx,UIComponent component,Object value) throws ValidatorException{
String ccnum=(String)value;
// get the card type form the binding object instead of the model object
HtmlSelectOneListBox cardChoiceComp= (HtmlSelectOneListBox) context.getApplication().createValueBinding("#{backing_requestscope.cardTypeChoice}").getValue(context);
int cardType = ((Integer)cardChoiceComp.getValue()).intValue();

boolean validCard = validateCard(ccnum,cardType);

if (validCard==false) throw new ValidatorException(new FacesMessage(" Invalid credit card format!!!!"));

}

private boolean validateCard(String ccnum,int cardType){
// visa cards always start with 4 and are either 13 or 16 digits in length
final int VISA=1;
// master cards are 16 digits in length and the first 2 digits range from 51 to 55
final int MASTER=2;
// Amex cards are 15 digits in length and the first 2 digits range from 34 to 37
final int AMEX=3;
switch(type) {
case VISA:
if ((ccnum.length() != 13 && ccnum.length() != 16) ||
Integer.parseInt(ccnum.substring(0,1))!=4)
return false;
break;
case MASTER:
if (ccnum.length() != 16 ||
Integer.parseInt(ccnum.substring(0,2)) <> 55)
return false;
break;
case AMEX:
if (ccnum.length() != 15 ||
(Integer.parseInt(ccnum.substring(0,2)) != 34 &&
Integer.parseInt(ccnum.substring(0,2))) != 37))
return false;
break;
}

// luhn validate
char[] charArr = ccnum.toCharArray();
int[] num = new int[charArr.length];
int total =0;
for(int i=0;i -1; i--){
if (alternate){ // multiply each even digit by 2 then add it to total
num[i] *=2;
if (num[i] > 9) num[i] -=9;
}
total +=num[i];
alternate = !alternate;

}
if (total % 10 != 0) return false;

return true;

}


}





In the MyCreditCardValidator class the most important thing to notice is how the value of card type is got since the validate method is called in the validation phase of a JSF life cycle the model objects are not set with the value hence the only way to get the value of a component other than the component that is being validated is thru the component binding.

Tuesday, December 22, 2009

Rollback JMS transactions in MDB Vs MDP

If you are writing an application which has a message driven bean or a message driven POJO you might want to put back the message in JMS destination if there is an exception in your application logic. In other words rollback the JMS transaction if there is an exception in onMessage. On a side note the acknowledgement mode of the message is considered to be AUTO_ACKNOWLEDGE instead of CLIENT_ACKNOWLEDGE as in the AUTO mode the messages are automatically removed from the queue unless a rollback is issue. Let us discuss how to issue a rollback in the case of an MDB first and then in a MDP.

Issuing a rollback in a Message Driven Bean (MDB)

A sample MDB implements MessageDrivenBean and MessageListener as follows




public class ExampleMDB implements javax.ejb.MessageDrivenBean, javax.jms.MessageListener{

javax.ejb.MessageDrivenContext context;

public void setMessageDrivenContext(javax.ejb.MessageDrivenContext aContext) {
context = aContext;
}
// ejbCreate and ejbRemove methods go hear.

// onMessage needs to be implemented here
public void onMessage(javax.jms.Message inMessage) {

// do your business logic here
// if error in business logic rollback by calling
context.setRollbackOnly();


}

}



The message driven context is set by the container in a container managed bean. The rollback is achieved by calling the context.setRollbackOnly() when this happens the message is put back in the queue. One should be carefull as the onMessage will be called repeatedly until the processing is fine and the rollback is not issued.

Issuing a rollback in a Message Driven POJO (MDP)

In a Spring MDP the task of issuing a rollback is as straightforward as just throwing a RunTimeException.




public class ExampleMDP implements javax.jms.MessageListener{


public void onMessage(Message message) throws RuntimeException{

// if error in business logic throw a RuntimeException
}
}




When the MDP is configured in the application context xml file make sure it is sessionTransacted, by setting it's value to true. Refer to my earlier article
how-to-write-message-driven-pojo

Monday, December 21, 2009

IllegalStateException in Spring's JmsTemplate

I have been using Spring's JmsTemplate to send messages to Queue's and Topic's in SUN Java Message Broker. The code to implement this was really simple you just configure a bean in your context called jmsTemplate with points to class org.springframework.jms.core.JmsTemplate, autowire this bean in your code and there you have all the methods to send all kinds of objects to your JMS destination.

Every thing worked fine, but now and then the jmsTemplate.convertAndSend method used to throw an org.springframework.jms.IllegalStateException: Session closed; nested exception is javax.jms.IllegalStateException: Session closed. Now I am not sure if this is very specific to my version of JMS broker, but some more reading in the spring forum showed that it happens in other JMS brokers aswell. There seems to be a bug with the JmsTemplate spring code especially when it is multithreaded. It seems that the JMS session is shared across multiple threads and at times one thread gets hold of a closed JMS session.

I had to find a way around this issue till the bug is fixed by handling the exception and using a custom boilerplate code for sending JMS messages,which I agree sucks big time.

Thursday, December 17, 2009

How to write a message driven pojo (MDP)

MDP is very simple to write in spring. There are quite a few examples out there. Follow these simple steps

Step1: Write a java class which implements javax.jms.MessageListener interface and implement the onMessage method



public class MyMessageListener implements javax.jms.MessageListener{


public void onMessage(Message message) throws RuntimeException{
try{
// do what you have to here
}catch(Throwable ex) {
throw new RuntimeException(ex);
}
}
}



Step2: Add the bean to your spring context.
In your spring context XML file that you have defined add the following entry. if you are using anotation then this is optional



<bean id="myListener" class="MyMessageListener"/>



Step3: Add a jms connection factory
Connection factories can been directly defined in the spring context in which case you need to also define the connection pooling. If your application is going to reside in an
application server then you can use JNDI to get the connection factory. If you are using the second approach you define the jndiTemplate then the connection factory




<bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"/>
<bean id="jmsQueueConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate"/>
</property>
<property name="jndiName">
<value>jms/QueueConnectionFactory</value>
</property>
</bean>



Where jms/QueueConnectionFactory is defined as a resouce in the application server along with connection pool settings.

Step4: Add the jms container to your spring context XML file.
This step attaches your POJO to a specific JMS resource (Queue/Topic)


<bean id="myJmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsQueueConnectionFactory"/>
<property name="destinationName" value="MyExampleQ"/>
<property name="sessionTransacted" value="false"/>
<property name="messageListener" ref="myListener" />
<property name="concurrentConsumers" value="1" />
<property name="receiveTimeout" value="30000" />
</bean>



And there you have it a simple message driven POJO called myListener mapping to the class MyMessageListener. It listens to messages in the queue named MyExampleQ
this is mentioned in the property destinationName. In this example sessionTransacted is set to false which means that if an exception occurs in onMessage method
the message will not be rolledback i.e. the message will be removed from the queue even if onMessage method failed. In most cases you might want the message to remain
in the queue if your operations in onMessage failed, in which case you need to set the value to true.

In this example concurrentConsumers is set to one you can use this property to better your performance by increasing this value.