LCDS Data management – Handling Java Exceptions
Posted by cornel | Filed under Flex, Java, LCDS/Blaze DS
I’m working on a small project using Flex and LCDS data management and yesterday I encountered a common use case: I wrote a method that was responsible for creating one user but only if several conditions were fulfilled. For example the username should not exist in the database, the postal code should be a valid one and the maximum length of the email should be 200 characters. It is not possible to perform the validation only on the client (because of security and data consistency problem). So my method checks this conditions and is throwing exceptions for any illegal case.
The Flex client should receive these exceptions and inform the user. I will present some code samples below in case that somebody else is interested in how to do that.
On the server part I overwrite the HibernateAssembler (create and update methods)
1:
2: public class UserAssembler extends HibernateAssembler{
3:
4: @Override
5: public void createItem(Object arg0) {
6: //Session session = hibernateManager.getSession(true);
7: User user = (User)arg0;
8: new UserService().createUser(
9: user.getName(),
10: user.getUsername(),
11: user.getPassword(),
12: user.getEmail());
13: }
14:
15: @Override
16: public void updateItem(Object arg0, Object arg1, List arg2) {
17: User user = (User)arg0;
18: new UserService().updateUser(
19: user.getId(),
20: user.getName(),
21: user.getUsername(),
22: user.getEmail());
23: }
24:
25:
26: }
The createUser and update user methods will throw an IllegalArgumentException with the proper message when the business validation fails.
1: if (findUser(userName) != null) {
2: throw new IllegalArgumentException("The user having the username " + userName + " already exists");
3: }
On the client side I have to add a fault handler to the destination. This handler is called every time when the dataservice fails on commit. For the sake of simplicity I’m assuming that it can fail only because the server validation was not successful.
1: userDataService = new DataService("User");//create the destination
2: userDataService.fill(usersArray,"com.test.User.mainFill",[]);//fill it
3: userDataService.addEventListener(DataServiceFaultEvent.FAULT,faultHandler);
The fault handler is defined below:
1: private function faultHandler(eventataServiceFaultEvent):void{
2: Alert.show(event.message.rootCause.cause.message);
3: userDataService.revertChanges(); //revert a
4: }
Assuming that the user wanted to create the username TEST and this already exists in database the following message will be displayed when the validation fails: “the user having the username TEST already exists”
How does it work? The Throwable object is serialized as any other object and is sent to the flex client packed in the event object. We can access it by “event.message.rootCause”. and we can extract the error message with “cause.message”.
Of course there are some situations when the error message can be more complex – in this case we can implement our custom exception handler and add more properties to it. Example:
1: public class UserValidationException extends Exception{
2:
3: private String email;
4: private String name;
5: private String errorMessage;
6:
7: public UserValidationException(String email, String name, String errorMessage) {
8: this.email = email;
9: this.name = name;
10: this.errorMessage = errorMessage;
11: }
12:
13: public String getEmail() {
14: return email;
15: }
16:
17: public String getName() {
18: return name;
19: }
20:
21: public String getErrorMessage() {
22: return errorMessage;
23: }
24:
25: }
1: if (findUser(userName) != null) {
2: throw new UserValidationException(email,username,"Username already exists");
3: }
On the client we can access our custom properties by event.message.rootCause.email, event.message.rootCause.userName, event.message.rootCause.errorMessage.
March 6th, 2009 at 12:01 pm
Hi !
I am using an AbstractAssembler. But there seems to be a problem with error handling.
While using “public void deleteItem(Object arg0)” if there is any error the DataServiceFaultEvent of the dataService is not called instead the DataConflictEvent and ResultEvent.RESULT are called. How is that both of them are called together. Any idea on this?
Thanks in advance.
March 8th, 2009 at 10:36 am
Hi,
I assume that you are using SqlAssembler or your custom Assembler which extends AbstractAssembler.
The conflict/result events are called if your delete method is throwing a DataSyncException
If you do not throw explicitly this error but you use SqlAssembler you can get this error if the deleteItem method will not be able to find the the row to delete in the table
Let me know if you have other questions.
September 17th, 2009 at 3:00 pm
Hi
in my pojo i have one object
@Column(name = “GRUPO”, unique = true, nullable = false, length = 45)
public String getGrupo() {
return this.grupo;
}
then i have a DAO Class to save object in database like this
public void save(Gruposdeusuarios entity) {
EntityManagerHelper.log(“saving Gruposdeusuarios instance”, Level.INFO,
null);
EntityManagerHelper.beginTransaction();
try {
getEntityManager().persist(entity);
EntityManagerHelper.commit();
EntityManagerHelper.log(“save successful”, Level.INFO, null);
} catch (RuntimeException re) {
EntityManagerHelper.log(“save failed”, Level.SEVERE, re);
EntityManagerHelper.rollback();
throw re;
}
}
then i have AbstractAssembler to make a call from flex to dao
public void createItem(Object entity){
GruposdeusuariosDAO dao = new GruposdeusuariosDAO();
dao.save((Gruposdeusuarios) entity);
}
if i duplicate de object i get this exception
GRAVE: save failed
javax.persistence.RollbackException: Exception [TOPLINK-4002] (Oracle TopLink Essentials – 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry ‘ENELDO’ for key ‘GRUPO’
Error Code: 1062
Call: INSERT INTO mydaniel.gruposdeusuarios (GRUPO) VALUES (?)
bind => [ENELDO]
the question is
how i can catch the Error Code:1062 and Duplicate Key Name “GRUPO” to flex dataservice on fault to tell flex user it trying to duplicate value
i using Tomcat 6 , Livecycle Data Service 2.5, mysql-connector-java-5.1.8-bin, JPA Toplink and Flex Builder 3.3
Thank
September 17th, 2009 at 5:55 pm
Hi Eneldo,
I wrote in my post – you just have to declare a fault handler for your dataservice. The fault will be invoked when you throw the error from the createItem
userDataService = new DataService(“User”);
userDataService.addEventListener(DataServiceFaultEvent.FAULT,faultHandler);
Your exception will be serialized and sent to the Flex client. In fault handler you can access all the details -take a look with a debugger on it.
May 14th, 2010 at 11:55 am
[...] The same approach from the point c) applies here. Basically your assembler – which is going to invoke some service to obtain/create data – will take care to translate the exceptions into something meaningful for the client. I wrote some time a short post about that here. [...]
August 24th, 2010 at 9:02 am
[...] The same approach from point c) applies here. Basically your assembler – which is going to invoke some service to obtain/create data – will take care of translating the exceptions into something meaningful for the client. I wrote some time ago a short post about that here. [...]
September 16th, 2011 at 1:09 pm
[...] The same approach from point c) applies here. Basically your assembler – which is going to invoke some service to obtain/create data – will take care of translating the exceptions into something meaningful for the client. I wrote some time ago a short post about that here. [...]