Sun Java System Mobile Enterprise Platform 1.0 Developer's Guide for Enterprise Connectors

Extending the BusinessObjectProvider Class

The BusinessObjectProvider class serves several purposes:

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:

    /**
     * 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;
    }