// Stateful Session Beans provide functionality that is a cross between // Stateless Session Beans and Entity Beans. While EBs are transactional // objects, SFSBs are only transactionally aware (but only if the Bean // implements the SessionSynchronization interface). // // In the first set of output below, the Bean was deployed with BMTD // and no explicit transaction boundaries. As a result, the Session- // Synchronization callback methods were never invoked. In the second // set of output, CMTD was specified and the transaction attribute of // Required was set on guess(). When setRollbackOnly() was invoked, // this produced a ServerException on the client, and the // afterCompletion() method received an argument of "false". package demos; import java.rmi.RemoteException; import javax.ejb.*; import java.util.Random; interface RIGuessGame extends EJBObject { int guess( int num ) throws RemoteException; } interface HIGuessGame extends EJBHome { RIGuessGame create( int max ) throws RemoteException, CreateException; } public class GuessGameBean implements SessionBean, SessionSynchronization { private SessionContext context; private Random rn = new Random(); private int answer, diff; public int guess( int num ) { System.out.println( " guess: num,ans " + num + "," + answer ); diff = Math.abs( answer - num ); if (num == answer) return 0; return (num < answer) ? -1 : 1; } public void ejbCreate( int max ) { answer = rn.nextInt( max ) + 1; System.out.println( "ejbCreate: " + answer ); } public void setSessionContext( SessionContext ctx ) { System.out.println( "setSessionContext:" ); context = ctx; } public void ejbRemove() { System.out.println( "ejbRemove: " + answer ); answer = 0; } public void ejbActivate() { System.out.println( "ejbActivate: " + answer ); } public void ejbPassivate() { System.out.println( "ejbPassivate: " + answer ); } // SessionSynchronization callback methods public void afterBegin() { System.out.println( "afterBegin: " + answer ); } public void beforeCompletion() { System.out.println( "beforeCompletion: " + answer ); if (diff == 0) { System.out.println( " ASKING FOR ROLLBACK" ); context.setRollbackOnly(); } } public void afterCompletion( boolean comp ) { System.out.println( "afterCompletion: completion is " + comp ); } } /********************************** *** with Bean-Managed Transaction Demarcation *** setSessionContext: ejbCreate: 15 guess: num,ans 11,15 guess: num,ans 33,15 setSessionContext: ejbCreate: 21 guess: num,ans 15,21 guess: num,ans 30,21 guess: num,ans 16,15 guess: num,ans 15,15 ejbRemove: 15 guess: num,ans 22,21 guess: num,ans 21,21 ejbRemove: 21 *** with Container-Managed Transaction Demarcation and *** *** a transaction attribute of Required for guess() *** setSessionContext: ejbCreate: 52 afterBegin: 52 guess: num,ans 33,52 beforeCompletion: 52 afterCompletion: completion is true afterBegin: 52 guess: num,ans 66,52 beforeCompletion: 52 afterCompletion: completion is true setSessionContext: ejbCreate: 31 afterBegin: 31 guess: num,ans 22,31 beforeCompletion: 31 afterCompletion: completion is true afterBegin: 31 guess: num,ans 44,31 beforeCompletion: 31 afterCompletion: completion is true afterBegin: 52 guess: num,ans 51,52 beforeCompletion: 52 afterCompletion: completion is true afterBegin: 52 guess: num,ans 52,52 beforeCompletion: 52 ASKING FOR ROLLBACK afterCompletion: completion is false ejbRemove: 52 afterBegin: 31 guess: num,ans 32,31 beforeCompletion: 31 afterCompletion: completion is true afterBegin: 31 guess: num,ans 31,31 beforeCompletion: 31 ASKING FOR ROLLBACK afterCompletion: completion is false ejbRemove: 31 **********************************/ package demos; import java.io.*; import javax.rmi.PortableRemoteObject; import javax.naming.*; public class GuessGameClient { public static void main( String[] args ) throws IOException { int guess, response=0, min=1, max=100; if (args.length > 0) max = Integer.parseInt( args[0] ); try { InitialContext ic = new InitialContext(); Object obj = ic.lookup("GuessGameHome"); HIGuessGame home = (HIGuessGame) PortableRemoteObject.narrow( obj, HIGuessGame.class ); RIGuessGame gg = home.create( max ); BufferedReader in = new BufferedReader( new InputStreamReader( System.in ) ); while (true) { System.out.print( "Enter guess (" + min + "-" + max + "): " ); guess = Integer.parseInt( in.readLine() ); try { response = gg.guess( guess ); } catch (java.rmi.ServerException ex) { System.out.println( " ROLLBACK ON THE SERVER" ); break; } if (response == 0) break; if (response < 0) if (min < guess) min = guess; if (response > 0) if (max > guess) max = guess; System.out.println( " too " + ((response < 0) ? "low" : "high") ); } System.out.println( "bells!! sirens!! confetti!!" ); gg.remove(); } catch (NamingException ex) { ex.printStackTrace(); } catch (javax.ejb.CreateException ex) { ex.printStackTrace(); } catch (javax.ejb.RemoveException ex) { ex.printStackTrace(); } } } /********************************** *** with Bean-Managed Transaction Demarcation *** D:\j2ee> java demos.GuessGameClient Enter guess (1-100): 11 too low Enter guess (11-100): 33 too high Enter guess (11-33): 16 too high Enter guess (11-16): 15 bells!! sirens!! confetti!! D:\j2ee> java demos.GuessGameClient Enter guess (1-100): 15 too low Enter guess (15-100): 30 too high Enter guess (15-30): 22 too high Enter guess (15-22): 21 bells!! sirens!! confetti!! *** with Container-Managed Transaction Demarcation and *** *** a transaction attribute of Required for guess() *** D:\j2ee> java demos.GuessGameClient Enter guess (1-100): 33 too low Enter guess (33-100): 66 too high Enter guess (33-66): 51 too low Enter guess (51-66): 52 ROLLBACK ON THE SERVER bells!! sirens!! confetti!! D:\j2ee> java demos.GuessGameClient Enter guess (1-100): 22 too low Enter guess (22-100): 44 too high Enter guess (22-44): 32 too high Enter guess (22-32): 31 ROLLBACK ON THE SERVER bells!! sirens!! confetti!! **********************************/