The BusinessObjectProvider class serves several purposes:
It allows you to retrieve all the business objects from a database by calling the getBusinessObjects() method.
It allows you to create new business objects by calling the newBusinessObject() method.
It provides access to a transaction manager and a session context.
For details on this class, see The BusinessObjectProvider Class.
For the MusicDB example, the class that extends BusinessObjectProvider is MusicAlbumProvider. Like the file for the MusicAlbum class, the MusicAlbumProvider.java source file begins by importing Java SE packages, along with com.synchronica logging packages and the required ECBO API classes. It then begins by setting up a logger and declaring some string constants, a JDBC connection object, its implementation of the TransactionManager class, and a user name object:
public class MusicAlbumProvider extends BusinessObjectProvider<MusicAlbum> { static Logger logger = Loggers.getLogger(MusicAlbumProvider.class); public static final String REPOSITORY_NAME = "MusicDbRepository"; public static final String MUSICDB_JNDI_DATASOURCE = "jdbc/musicdb"; public static final String DB_USER_NAME = "musicdbuser"; public static final String DB_USER_PASS = "musicdbpass"; Connection sqlConnection = null; MusicAlbumTransactionManager transactionManager; String username;
The REPOSITORY_NAME value is identical to the repository name specified in the resource file for the Enterprise Connector. In the MusicDB sample, the resource file is named MusicDbRepository.xml and defines a repository named MusicDbRepository.
The code implements two forms of the business object constructor: the no-argument constructor specified by the API and a one-argument form that takes a user name as argument for testing purposes.
Next, the code implements the two lifecycle methods for the BusinessObjectProvider class, initialize and terminate, which coincide with the start and end of a synchronization session.
The initialize method allocates resources required for a synchronization session or for database authentication. In this case, the code does the following:
Looks up a JDBC datasource.
Retrieves the username value from the SessionContext for use in updating the album table in the database.
Obtains a JDBC connection using the credentials established for the MusicDB database when it was created.
Instantiates a transaction manager.
/** * Creates a connection to the {@link #MUSICDB_JNDI_DATASOURCE} * database. */ @Override public void initialize() { logger.debug("Initializing provider " + this); try { Context jndiContext = new InitialContext(); DataSource ds = null; // If unable to get JNDI datasource, use local one for testing try { ds = (DataSource) jndiContext.lookup(MUSICDB_JNDI_DATASOURCE); } catch (NoInitialContextException e) { ds = new MusicDbDataSource(); // testing only! } // Get database credentials from provider's context SessionContext sessionContext = getSessionContext(); username = sessionContext.getUsername(); // Get connection using default credentials sqlConnection = ds.getConnection(DB_USER_NAME, DB_USER_PASS); // Init transaction manager transactionManager = new MusicAlbumTransactionManager(); } catch (Exception ex) { throw new RuntimeException(ex); } }
The implementation of the terminate method releases any resources allocated by the initialize method. In this case, it closes the JDBC connection.
/** * Closes a connection to the {@link #MUSICDB_JNDI_DATASOURCE} * database. */ @Override public void terminate() { logger.debug("Terminating provider " + this); try { if (sqlConnection != null) { sqlConnection.close(); } } catch (Exception e) { throw new RuntimeException(e); } }
The implementation of the getRepositoryName method specifies the string value declared at the beginning of the class. The repository in question is the JCR repository that is used for communication between the Gateway Engine and the Enterprise Connector and that is specified by the resource file.
/** * {@inheritDoc} */ @Override public String getRepositoryName() { return REPOSITORY_NAME; }
The implementation of the getBusinessObjects method uses a JDBC query to retrieve all the albums for the user username from the database, instantiates a MusicAlbum object for each retrieved album, and adds it to an ArrayList of albums.
/** * {@inheritDoc} */ @Override public List<MusicAlbum> getBusinessObjects() { logger.debug("Getting objects from provider " + this); Statement stmt = null; List<MusicAlbum> albums = null; try { stmt = sqlConnection.createStatement(); // Read all music albums and store them in array albums = new ArrayList<MusicAlbum>(); ResultSet rs = stmt.executeQuery( "SELECT * FROM album WHERE username = '" + username + "'"); while (rs.next()) { MusicAlbum album = new MusicAlbum(this); album.setName(rs.getString(1)); album.setArtist(rs.getString(2)); album.setDatePublished(rs.getString(3).replace("-", "")); album.setRating(rs.getInt(4)); albums.add(album); } rs.close(); } catch (Exception ex) { throw new RuntimeException(ex); } finally { if (stmt != null) { try { stmt.close(); } catch (Exception e) { /* ignore !*/ } } } return albums; }
The implementation of the newBusinessObject method is much simpler: it calls the one-argument constructor for MusicAlbum.
/** * {@inheritDoc} */ @Override public MusicAlbum newBusinessObject() { return new MusicAlbum(this); }
The provider class also implements the helper method getSQLConnection, which returns the JDBC connection that was instantiated by the initialize method. This method is called by the MusicAlbum class.
/** * Returns a connection object that can be used to * execute SQL commands. */ public Connection getSQLConnection() { return sqlConnection; }
The provider class also implements a getUsername method that is called by the MusicAlbum class's utility methods:
/** * Returns the user name logged into the session that * created this provider. */ public String getUsername() { return username; }
The getTransactionManager method retrieves the MusicAlbumTransactionManager that is declared at the beginning of the file, instantiated in the initialize method, and implemented within the MusicAlbumProvider.java file.
/** * Returns a transaction manager that uses JDBC to start, * stop and abort transactions. */ @Override public MusicAlbumTransactionManager getTransactionManager() { return transactionManager; }