Brace yourselves, here is the complete code :-

  | //Package:      Security Objects
  | //Class:        SecurityRoleSetBean
  | //Version:      1.0
  | //Copyright:    Copyright (c) 2002
  | //Author:       James Strachan
  | //Company:      Milton Software Components
  | //Description:  Entity Bean holds a set of all roles known in the application.
  | //Amendment History:-
  | //Version   Date        Author      Modification
  | //0.a       23/05/2002  JAS         Conception
  | //0.b       02/01/2003  JAS         Convert to Log4J Error Logger
  | //1.0       18/02/2003  JAS         Release (no changes).
  | 
  | package org.milton.services.security;
  | 
  | import java.util.ArrayList;
  | import java.util.Collection;
  | import java.util.Iterator;
  | 
  | import javax.naming.Context;
  | import javax.naming.NamingException;
  | import javax.naming.InitialContext;
  | 
  | import java.rmi.RemoteException;
  | import javax.rmi.PortableRemoteObject;
  | 
  | import javax.ejb.*;
  | 
  | import java.sql.Connection;
  | import java.sql.PreparedStatement;
  | import java.sql.ResultSet;
  | import javax.sql.DataSource;
  | import java.sql.SQLException;
  | 
  | import org.apache.log4j.Logger;
  | 
  | import org.milton.services.common.EJBNameFactory;
  | 
  | /**
  |  * This class is a singleton Entity Bean that stores the master set of Roles.
  |  * <p>
  |  * We enforce the singleton restriction by checking on the key used.
  |  * <p>
  |  * Calling applications should use the static String <code>SINGLETON_NAME</code>
  |  * as the key for the Entity.
  |  * @author J.A.Strachan
  |  * @version 1.0
  |  */
  | public class SecurityRoleSetBean implements EntityBean {
  | 
  |   private static final String DATASTORE_ADDRESS = 
EJBNameFactory.MILTON_DATASTORE_ADDRESS;
  | 
  |   private EntityContext ctx;
  | 
  |   /**
  |    * Log4J Logger for error logging.
  |    */
  |   private static Logger logger;
  | 
  |   /**
  |    * The identifier for a Role Set.  Not of much value as this bean is a singleton.
  |    * Is required by EJB, and must be public to be available for use by the EJB 
container.
  |    */
  |   public String defaultName;
  | 
  |   /**
  |    * Set of Roles loaded from the database.
  |    */
  |   private ArrayList roles = new ArrayList();
  | 
  |   /**
  |    * Flag to say whether roles have changed.
  |    */
  |   private boolean rolesChanged = false;
  | 
  |   /**
  |    * This static string will be used to define the key for the Singleton Role Set.
  |    */
  |   public static final String SINGLETON_NAME = "default";
  | 
  |   /**
  |    * No argument constructor - initialise Logger.
  |    */
  |   public SecurityRoleSetBean() {
  | 
  |     if ( logger == null )  {
  |       logger = Logger.getLogger( this.getClass() );
  |       }
  | 
  |   }
  | 
  |   /**
  |    * Get the set of Roles.
  |    * @return ArrayList - the master set of Roles.
  |    */
  |   public ArrayList getRoles()  {
  | 
  |     return roles;
  | 
  |     }
  | 
  |   /**
  |    * Set the master set of Roles.
  |    * Check the roles to see if any have changed, and set the roles flag if so.
  |    * @param roles
  |    */
  |   public void setRoles( ArrayList roles )  {
  | 
  |     rolesChanged = !this.roles.equals(roles);
  |     this.roles = roles;
  | 
  |   }
  | 
  |   /**
  |     * Standard create method.
  |     * <p>
  |     * This method should <b>NEVER</b> be called unless the underlying database
  |     * has first been emptied of data.
  |     * @param defaultName
  |     * @param roles
  |     * @return String defaultName - primary key of created object.
  |     * @throws RemoteException
  |     * @throws CreateException
  |     */
  |   public String ejbCreate( String defaultName, ArrayList roles )
  |       throws RemoteException, CreateException {
  | 
  |     Connection conn = null;
  |     PreparedStatement statement = null;
  |     InitialContext context = null;
  |     DataSource dataSource;
  |     int rowCount = 0;
  | 
  |     logger.info( "Create called : " + defaultName );
  | 
  |     // Check that the caller is using the only legal name.
  |     if ( !defaultName.equals(SINGLETON_NAME) )  {
  |       throw new CreateException( "Must use name " + SINGLETON_NAME );
  |       }
  | 
  |     // Set the primary key.
  |     this.defaultName = defaultName;
  |     this.roles = roles;
  | 
  |     String sqlStatement = "INSERT into SecurityRoleSet ( rolename ) " +
  |       "values ( ? )";
  | 
  |     try  {
  | 
  |       // Get a database connection.
  |       context = new InitialContext();
  |       dataSource = (DataSource) context.lookup( DATASTORE_ADDRESS );
  |       conn = dataSource.getConnection();
  | 
  |       // Prepare a statement and set parameters.
  |       statement = conn.prepareStatement( sqlStatement );
  | 
  |       Iterator i = roles.iterator();
  |       while ( i.hasNext() )  {
  |         statement.setString( 1, (String) i.next() );
  |         // Execute the statement.
  |         statement.execute();
  |         rowCount++;
  |         }
  |       logger.debug( "Inserted " + rowCount + " rows" );
  |       rolesChanged = false;       // Set roles changed flag to false.
  |       }
  |     // Error in lookup ?
  |     catch( NamingException ne )  {
  |       logger.error( ne.getMessage(), ne );
  |       throw new CreateException( ne.getMessage() );
  |       }
  |     // Error in SQL statement ?
  |     catch( SQLException sqe )  {
  |       logger.error( sqe.getMessage(), sqe );
  |       throw new CreateException( sqe.getMessage() );
  |       }
  |     finally {
  |       try  {
  |         if ( statement != null )  {
  |           statement.close();
  |           }
  |         if ( conn != null )  {
  |           conn.close();
  |           }
  |         }
  |       catch ( SQLException e1 ) {}
  |       }
  | 
  |     return this.defaultName;
  | 
  |   }
  | 
  |   /**
  |     * No work required here - but skeleton is required by EJB.
  |     * @param defaultName
  |     * @param roles
  |     */
  |   public void ejbPostCreate( String defaultName, ArrayList roles )  {}
  | 
  |   /**
  |     * This standard EJB method locates a RoleSet using the Primary Key.
  |     * <p>
  |     * Note that Role Set is a singleton - so this method is stripped of all code.
  |     * @param defaultName - the Key of the requested Security Object.
  |     * @return String defaultName - the Identifier if the RoleSet was located.
  |     * @throws RemoteException
  |     * @throws ObjectNotFoundException
  |     * @throws FinderException
  |     */
  |   public String ejbFindByPrimaryKey( String defaultName ) throws RemoteException,
  |     ObjectNotFoundException {
  | 
  |     if ( !defaultName.equals(SINGLETON_NAME) ) {
  |       throw new ObjectNotFoundException();
  |       }
  | 
  |     this.defaultName = defaultName;
  |     return defaultName;
  | 
  |   }
  | 
  |   /**
  |     * This standard EJB method loads the Role Set.  To fit EJB standards, the
  |     * primary key - defaultName - is read from the Context.
  |     * <p>
  |     * @throws RemoteException
  |     */
  |   public void ejbLoad() throws RemoteException {
  | 
  |     Connection conn = null;
  |     PreparedStatement statement = null;
  |     InitialContext context = null;
  |     DataSource dataSource;
  |     ResultSet rs;
  | 
  |     String sqlStatement = "SELECT rolename " +
  |       "from SecurityRoleSet order by rolename";
  | 
  |     defaultName = (String) ctx.getPrimaryKey();
  | 
  |     logger.info( "Load called : " + defaultName );
  | 
  |     try  {
  | 
  |       // Get a database connection.
  |       context = new InitialContext();
  |       dataSource = (DataSource) context.lookup( DATASTORE_ADDRESS );
  |       conn = dataSource.getConnection();
  | 
  |       // Prepare and execute the statement.
  |       statement = conn.prepareStatement( sqlStatement );
  |       statement.execute();
  | 
  |       // Loop through the SQL result set, building the ArrayList to be returned.
  |       // Trim the strings.
  |       roles.clear();
  |       rs = statement.getResultSet();
  |       while( rs.next() )  {
  |         roles.add( rs.getString(1).trim() );
  |         }
  |       rolesChanged = false;         // Set flag - roles not changed since load.
  |       }
  |     // Lookup failed ?
  |     catch( NamingException ne )  {
  |       logger.error( ne.getMessage(), ne );
  |       throw new RemoteException( ne.getMessage() );
  |       }
  |     // Something nasty in the woodshed ?
  |     catch( SQLException sqe )  {
  |       logger.error( sqe.getMessage(), sqe );
  |       throw new RemoteException( sqe.getMessage() );
  |       }
  |     finally {
  |       try  {
  |         if ( statement != null )  {
  |           statement.close();
  |           }
  |         if ( conn != null )  {
  |           conn.close();
  |           }
  |         }
  |       catch ( SQLException e1 ) {}
  |       }
  | 
  |   }
  | 
  |   /**
  |     * This standard EJB method physically deletes a Role Set from the database.
  |     * <p>
  |     * This should <b>NEVER</b> be called.
  |     * <p>
  |     * Thinks - why not delete the code so it doesn't matter if it is ?
  |     * @throws RemoteException
  |     * @throws RemoveException
  |     */
  |   public void ejbRemove() throws RemoteException, RemoveException {
  | 
  |     Connection conn = null;
  |     PreparedStatement statement = null;
  |     InitialContext context = null;
  |     DataSource dataSource;
  | 
  |     String sqlStatement = "DELETE from SecurityRoleSet";
  |     int rowCount;
  | 
  |     defaultName = (String) ctx.getPrimaryKey();
  | 
  |     logger.info( "Remove called : " + defaultName );
  | 
  |     try  {
  | 
  |       context = new InitialContext();
  |       dataSource = (DataSource) context.lookup( DATASTORE_ADDRESS );
  |       conn = dataSource.getConnection();
  | 
  |       statement = conn.prepareStatement( sqlStatement );
  |       rowCount = statement.executeUpdate();
  |       logger.debug( "Removed " + rowCount + " rows" );
  |       }
  |     catch( NamingException ne )  {
  |       logger.error( ne.getMessage(), ne );
  |       throw new RemoveException( ne.getMessage() );
  |       }
  |     catch( SQLException sqe )  {
  |       logger.error( sqe.getMessage(), sqe );
  |       throw new RemoveException( sqe.getMessage() );
  |       }
  |     finally {
  |       try  {
  |         if ( statement != null )  {
  |           statement.close();
  |           }
  |         if ( conn != null )  {
  |           conn.close();
  |           }
  |         }
  |       catch ( SQLException e1 ) {}
  |       }
  | 
  |   }
  | 
  |   /**
  |     * Standard EJB method to store a Role Set in persistent data.
  |     * <p>
  |     * For simplicity, this just calls the ejbRemove and ejbCreate methods.
  |     * <p>
  |     * This is simpler, and probably quicker, than working through the old and new
  |     * sets of Roles, identifying changes, and inserting or deleting individual 
rows.
  |     * @throws RemoteException
  |     */
  |   public void ejbStore() throws RemoteException {
  | 
  |     try  {
  |       if ( rolesChanged )  {
  |         ejbRemove();
  |         ejbCreate( this.defaultName, this.roles );
  |         }
  |       }
  |     catch ( Exception e )  {
  |       logger.error( e.getMessage(), e );
  |       throw new RemoteException( "Error in store", e );
  |       }
  | 
  |   }
  | 
  |   // Standard EJB methods below here.
  | 
  |   public void setEntityContext(EntityContext ctx) throws RemoteException {
  | 
  |     this.ctx = ctx;
  | 
  |   }
  | 
  |   public void unsetEntityContext() throws RemoteException {
  | 
  |     ctx = null;
  | 
  |   }
  | 
  |   public void ejbActivate() throws RemoteException {
  |   }
  | 
  |   public void ejbPassivate() throws RemoteException {
  |   }
  | 
  | 
  | }
  | 

Answering David's questions :-

There should be one and only one instance of an Entity Bean with a given identifier 
within the server.  We don't need to configure the server for this - it should be 
guaranteed.  I use an artificial, published identifier to ensure that clients always 
look up the same Entity Bean.

If several clients attempt to access the Entity bean, then JBoss locks the Entity Bean 
on behalf of the first user, and stalls other requests until the first access 
completes.

This may become a problem with David's application.  The method call that returns data 
to the client may take some time to serialise the list and to pass the list across the 
network to the client.  Depending on the number of clients, the Entity Bean may be 
overloaded and become a bottleneck.

The solution to that problem would be to use a pool of Stateless Session Beans around 
the Entity Bean.  The client accesses the Session Bean.  The Session Bean gets a 
reference to the list from the Entity Bean (which is very quick), releases the Entity 
Bean, and can then spend as long as it likes passing the data to the client.

In that approach, you would need to build a new list when reloading data from the 
database - to avoid overwriting the list that Session Beans mayu be processing.

James



View the original post : 
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=3838989#3838989

Reply to the post : 
http://www.jboss.org/index.html?module=bb&op=posting&mode=reply&p=3838989


-------------------------------------------------------
This SF.Net email is sponsored by The 2004 JavaOne(SM) Conference
Learn from the experts at JavaOne(SM), Sun's Worldwide Java Developer
Conference, June 28 - July 1 at the Moscone Center in San Francisco, CA
REGISTER AND SAVE! http://java.sun.com/javaone/sf Priority Code NWMGYKND
_______________________________________________
JBoss-user mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to