jQuery in Action, 2nd edition*
The moose likes EJB Certification (SCBCD/OCPJBCD) and the fly likes Doubt on Sun Assessment Q26 Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of OCA/OCP Java SE 7 Programmer I & II Study Guide this week in the OCPJP forum!
JavaRanch » Java Forums » Certification » EJB Certification (SCBCD/OCPJBCD)
Bookmark "Doubt on Sun Assessment Q26" Watch "Doubt on Sun Assessment Q26" New topic
Author

Doubt on Sun Assessment Q26

Chaminda Amarasinghe
Ranch Hand

Joined: May 17, 2006
Posts: 402
Hi Guys,

This is question of Sun Free Assessment. According to them correct answer is 1). Can some one explain y 5) is incorrect (i.e why beforeCompletion and afterCompletion are not called after bean method execution)


26. Given an excerpt from a stateful session bean:

10. @Stateful
11. public class MyStatefulBean implements MyStateful, SessionSynchronization {
12. @Resource SessionContext ctx;
13. public void afterCompletion(boolean f) {}
14. public void beforeCompletion() { ctx.setRollbackOnly(); }
15. public void afterBegin() {}
16. @Remove
17. public void inc() {}
18. }
The MyStateful interface is a local business interface that declares inc to be a business method. No deployment descriptor is used. A stateless session bean using container-managed transactions has a business method that acts as a client:

20. @TransactionAttribute(TransactionAttributeType.REQUIRED)
21. public String doIt() {
22. ms.inc();
23. }
The method doIt is called without a transactional context. Which order properly reflects the order of method invocation?

1) doIt, afterBegin, inc
2) doIt, inc, afterBegin, beforeCompletion
3) doIt, inc, beforeCompletion, afterBegin, afterCompletion
4) doIt, inc, afterBegin, beforeCompletion, afterCompletion
5) doIt, afterBegin, inc, beforeCompletion, afterCompletion


Thanks
Cham
[ November 18, 2008: Message edited by: Chaminda Amarasinghe ]
Amandeep Singh
Ranch Hand

Joined: Jul 17, 2008
Posts: 844
Chaminda,

The method doIt is called without a transactional context. And when we call doIt() method, it attribute requires that whenever it is called, a transaction is required. So here container will create a new transaction.

As the client state is not here maintained under cache or better to say under 1 transaction, so SessionSynchronization method's are not called.

Even i have tried this example, SessionSynchronization method's were not called during bean transition.

Hope this addtnl Info help's you

---------------Session synchronization
Although using CMT doesn�t give you full control over when a transaction is started,
committed, or rolled back, you can be notified about the transaction�s lifecycle
events. This is done simply by having your CMT bean implement the javax.
ejb.SessionSynchronization interface. This interface defines three methods:
■ void afterBegin()�Called right after the container creates a new transaction
and before the business method is invoked.
■ void beforeCompletion()�Invoked after a business method returns but
right before the container ends a transaction.
■ void afterCompletion(boolean committed)�Called after the transaction
finishes. The boolean committed flag indicates whether a method was
committed or rolled back.
Implementing this interface in a stateful session bean can be considered close to
having a poor man�s persistence mechanism, because data can be loaded into the
bean when the transaction starts and unloaded right before the transaction finishes,
while the afterCompletion callback can be used to reset default values.
However, you can make a valid argument that since session beans are supposed
to model processes, if it makes sense to cache some data and synchronize with
the database as a natural part of a process, then this practice is just fine, if not
fairly elegant.
Note this facility doesn�t make much sense in a stateless session bean or MDB
where data should not be cached anyway; therefore, the interface is not supported
for those bean types.
-------------------------------


SCJP 1.4, SCWCD 5, SCBCD 5, OCPJWSD 5,SCEA-1, Started Assignment Part 2
My blog- http://rkydesigns.blogspot.com
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

Check "4.4 Stateful Session Bean State Diagram" : If the Remove method completes successfully or if the Remove methods throws an application exception for which retainIfException is not true or if a system exception is thrown, SessionSynchronization methods are not called on the bean instance.

I think that it's important for SCBCD to refer to the specification. Download it if you haven't done it already.


[My Blog]
All roads lead to JavaRanch
Chaminda Amarasinghe
Ranch Hand

Joined: May 17, 2006
Posts: 402
Thanks Guys,

That part havn't caught my eye

Would be helpful someone, let me complete the section.

If the Remove method completes successfully or if the Remove methods throws an application exception for which retainIfException is not true or if a system exception is thrown, SessionSynchronization methods are not called on the bean instance. If an application exception is thrown for which retainIfException is true,the bean is neither destroyed nor discarded, and SessionSynchronization methods, if any, are called on the instance at the end of transaction.

The container must call the afterBegin, beforeCompletion, and afterCompletion methods if the session bean class implements, directly or indirectly, the SessionSynchronization interface. The container does not call these methods if the session bean class does not implement the SessionSynchronization interface


PS: Spec says "SessionSynchronization methods are not called on the bean instance" So why afterBegin has been called in the previous question. ?
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

There is a special case when an application exception is thrown and the retainIfException attribute of the @Remove annotation has been set to true. In this case, the bean will not be discarded, and the SessionSynchronization methods will be invoked. Concerning the afterBegin method, this method will be called when the remove method is being invoked. You can imagine that the container does not know how the remove method is going to behave, so it will call afterBegin in any case.
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

I think it would be a good exercise to make a Stateful session bean, implement SessionSynchronization, and try the various scenario (@Remove, @Remove(retainIfException=true), throwing an application exception whose rollback is set to true, throwing an application exception whose rollback is set to false, throwing a system exception).
Chaminda Amarasinghe
Ranch Hand

Joined: May 17, 2006
Posts: 402
Yes I tried,

The sun's answer is correct. My question is why container calls afterBegin? Spec says SessionSynchronization methods are not called. afterBegin is a SessionSynchronization method, hence it also should not be called for Remove method. Isnt it?
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

You're right, I think they just didn't bother to say "except afterBegin". If you were a container provider, you would have no choice but calling afterBegin anyway.
Amandeep Singh
Ranch Hand

Joined: Jul 17, 2008
Posts: 844
well guy's, in my stateful session bean, i implemented SessionSynchrinization method, i tried example's but it's method were never called.
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

Is your method running in a transactional context ? Can you post your code ?
Amandeep Singh
Ranch Hand

Joined: Jul 17, 2008
Posts: 844
Sure,

here is my class

---------------
package pack;

import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.ejb.EJBContext;
import javax.ejb.EJBException;
import javax.ejb.PostActivate;
import javax.ejb.PrePassivate;
import javax.ejb.Remove;
import javax.ejb.SessionContext;
import javax.ejb.SessionSynchronization;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerService;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.ejb.TransactionManagement;
import javax.ejb.TransactionManagementType;
import javax.interceptor.Interceptors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.sql.DataSource;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;



@Stateful(name="AccountCreatorBean", mappedName="ejb/SimpleJNDIName")
@TransactionManagement(TransactionManagementType.CONTAINER)
public class AccountCreatorBean implements AccountCreator, SessionSynchronization{
// So either use the persistenceContext or Resource, both do the same things.
// @PersistenceContext(unitName="actionBazaar")
@Resource(name= "jdbc/ActionBazaarDS")
private DataSource dataSource;
private EntityManager em;
private Connection connection;

private BioGraphicalInfo biographicainfo;

@Resource
TimerService timerservice;

@Resource
EJBContext context;

public AccountCreatorBean(){

}

@PostConstruct
@PostActivate
public void openConnection(){
try {
connection = dataSource.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

public void enterBiographicalInfo(BioGraphicalInfo info){
this.biographicainfo = info;
}
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
@Interceptors(AccountCreatorLogger.class)
public String createAccount() throws CreateAccountException, NotSupportedException, SystemException {
String result = null;
try {
// if (!context.isCallerInRole("ANONYMOUS")){
//throw new SecurityException("No right's to insert record's into account");
// }
// UserTransaction transaction = context.getUserTransaction();
// transaction.begin();
Statement statement = connection.createStatement();
statement.execute(
"insert into account (name, number) values ('"+ biographicainfo.getName()
+"',"+ biographicainfo.getAge() + ")"
);
Timer time = timerservice.createTimer(15, 15, biographicainfo.getName());
result = "getInfo" + (String) time.getInfo() + "getNextTimeout()" + time.getNextTimeout().toString()
+ "getNextTimeout() " + time.getNextTimeout().toString() ;
statement.close();
// System.out.println("context.getRollbackOnly() " + context.getRollbackOnly());
// System.out.println("transaction.getStatus() =" + transaction.getStatus());
// System.out.println("context.getCallerIdentity() =" + context.getCallerIdentity());
System.out.println("context.getCallerPrincipal() =" + context.getCallerPrincipal());
System.out.println("context.getCallerPrincipal().getName() =" + context.getCallerPrincipal().getName());;
// transaction.commit();
}
catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();

context.setRollbackOnly();
return e.toString();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//catch (RollbackException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
//} catch (HeuristicMixedException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
//} catch (HeuristicRollbackException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
//}
return result;
}
@Timeout
public void monitorName(Timer timer){
String name = (String)timer.getInfo();
System.out.println("Monitor name thru timeout " + name);
}

@PrePassivate
@PreDestroy
public void cleanUp(){
try {
connection.close();
connection = null;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
@Remove
public void cleanConnection(){
biographicainfo = null;


}

@Override
public void afterBegin() throws EJBException, RemoteException {
// TODO Auto-generated method stub
System.out.println("After begin method");
}

@Override
public void afterCompletion(boolean arg0) throws EJBException,
RemoteException {
// TODO Auto-generated method stub
System.out.println("After completion method");
}

@Override
public void beforeCompletion() throws EJBException, RemoteException {
// TODO Auto-generated method stub
System.out.println("Before completion method");
}


}
-------------------------

[ November 19, 2008: Message edited by: Amandeep Singh ]
[ November 19, 2008: Message edited by: Amandeep Singh ]
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

1. Why did you set the @Override annotation to SessionSynchronization's methods ?
2. How did you use this bean ?
Amandeep Singh
Ranch Hand

Joined: Jul 17, 2008
Posts: 844
1) In Eclipse IDE, actually i implemented the interface SessionSynchronization, so it automatically implemented the unimplemented method of this interface. That's how the override annotation's came up.

2) I used to call this bean from this client code-

----------------
import javax.ejb.EJB;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.NotSupportedException;
import javax.transaction.SystemException;

import pack.AccountCreator;
import pack.BioGraphicalInfo;
import pack.CreateAccountException;



@EJB
public class AccountCreatorClient {

private static AccountCreator accountCreatorBean;
private static BioGraphicalInfo bioGraphicalInfo;
public static void main(String[] args) {
try {
InitialContext ctx = new InitialContext();
accountCreatorBean = (AccountCreator)ctx.lookup("ejb/SimpleJNDIName");
bioGraphicalInfo = new BioGraphicalInfo("test17", 18, "M","Alpharetta");
accountCreatorBean.enterBiographicalInfo(bioGraphicalInfo);
String result;
try {
result = accountCreatorBean.createAccount();
System.out.println(result);
} catch (CreateAccountException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NotSupportedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SystemException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

} catch (NamingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}
-------------------------
[ November 19, 2008: Message edited by: Amandeep Singh ]
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

1) Implementing SessionSynchronization methods should not set the @Override annotation. It should not even compile.
2) You're not calling the session bean's remove method
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

Another thing, how can you use the timer service ? Timers cannot be created for stateful session beans. That's a lot of errors, making me wonder how you could compile and deploy such a class.
Amandeep Singh
Ranch Hand

Joined: Jul 17, 2008
Posts: 844

1) Implementing SessionSynchronization methods should not set the @Override annotation. It should not even compile.
2) You're not calling the session bean's remove method


1) it is set to override by the compiler and so it is compiling.

2) I am not calling the session bean's remove method. Isn't this part of bean lifecycle method, so when the container see's @Remove, it call's the code inside it.



Another thing, how can you use the timer service ? Timers cannot be created for stateful session beans. That's a lot of errors, making me wonder how you could compile and deploy such a class.



1) As you can see there is alot of commenting in code and also many import statement's done. Because intially i used this class as Stateful Bean. So at that time no timers were present. Then to avoid writing more code project, i made this class Stateless bean and added the timer. Then you asked for the code. So hurriedly, to show my previous change's to you, i changed it from Stateless to Stateful, just to show you the code.
Sorry i did hurriedly, so didn't checked out.
Christophe Verré
Sheriff

Joined: Nov 24, 2005
Posts: 14688
    
  16

2) I am not calling the session bean's remove method. Isn't this part of bean lifecycle method, so when the container see's @Remove, it call's the code inside it.

No, you're responsible for calling it, otherwise the container will leave the stateful beans until it dies (e.g. client inactivity timeout).

Sorry i did hurriedly, so didn't checked out.

It's ok But it's difficult to help with erronous code.
Chaminda Amarasinghe
Ranch Hand

Joined: May 17, 2006
Posts: 402
Guys,

1. @Override
Its not an issue

2. Timerservice in statefull
Big No

3. Use ENC
You cant use

with InitialContext

4. You should call remove method.
[ November 20, 2008: Message edited by: Chaminda Amarasinghe ]
[ November 20, 2008: Message edited by: Chaminda Amarasinghe ]
Sudarshan Sreenivasan
Ranch Hand

Joined: Jun 28, 2007
Posts: 188

How is the business method being called before afterBegin() ?

Should'nt the transaction start first and then the afterBegin() method get invoked and subsequently the business methods ?
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Doubt on Sun Assessment Q26